动机,其实自己是非常喜欢写作的,那些年中二年纪写了很多自己生活的方方面面,与那时候在QQ空间和新浪博客相比,现在自己算是弃笔了一般。想把自己看到的东西慢慢总结一下,以前中二幼稚起来觉得这些都太简单,不要写了,会丢人,其实根本没什么人光顾我的博客的。更根本的原因是健忘又懒惰,离不开烂笔头的帮助,很多知识与知识之间也不是具有逻辑链条,可以一条一条逐条推出来,就像捡贝壳一样,还是要自己一个一个捡起来才放心和靠谱,所以自己就在这里记下来,凡是因为这个目的而记录的,都写到《游记》里面去。
看了基本机器学习的书,觉得还是周志华老师讲得最好,把老师的思路总结起来呢,就是 这篇在知乎的文章讲得内容,方便了理解了老师书后复习用,这里引用下:
原文: BP神经网原理及C语言实现 配套代码 其它 :BPNN-Face-Recognition-For-Parallel
其它:....我觉得也不错,适合我这个MPI初学者。
BP神经网络及其C语言实现
BP神经网络是目前为止最为成功的神经网络模型之一,本文首先介绍BP神经网络的基本概念和理论推导,最后给出具有训练、仿真及实际拟合功能的C语言实现。
本文的理论部分全部来源于周志华《机器学习》,P97-P106,如需详细了解,请查阅本书。
1. 基本概念
- 神经网络:由简单的神经元组成的广泛互联的网络,其具有适应性,可以模拟生物神经系统对真实世界所做出的交互反应。
- 神经元模型:神经元模型是神经网络中的基本模型,单个神经元可以接收网络中其他神经元的信息,如果接收的信息超过阈值,则此神经元被激活,接着向其他神经元发送信息。
- M-P神经元模型:M-P神经元模型是典型的神经元模型,其基本结构如图1所示。
图1 M-P神经元模型
在这个模型中,神经元接收来自n个其他神经元传递过来的输入信号,这些输入信号通过带权重的连接进行传递,神经元接收到的总输入值将与神经元的阈值进行比较,然后通过“激活函数”处理产生神经元的输出。
- Sigmoid函数:sigmoid是最常用的激活函数,如图2所示。
图2 sigmoid函数
其函数表达式为
- 多层前馈神经网络(multi-layer feedforward neural networks):基本结构如图3所示,此种结构的圣经网络,每层神经元与下一层神经元全连接,神经元之间不存在同层连接,也不存在跨层连接。其网络层次包含3层,其中输入层神经元用于接收外界输入,隐层与输出层神经元对信号进行加工,最终结果由输出层神经元输出。
图3 多层前馈神经网络
- 神经网络的学习过程:根据训练数据来调整神经元之间的连接权以及每个功能神经元的阈值,换言之,神经网络学习到的东西蕴含在连接权与阈值中。
2. BP神经网络理论推导
2.1 BP神经网络结构
BP神经网络是目前为止最为成功的神经网络算法之一,其学习方式采用标准梯度下降的误差逆传播(error BackPropagation)的方式,以下介绍的基本BP神经网络为3层前馈神经网络。
图4 BP神经网络模型
对于BP神经网络,我们需要使用训练数据集对其进行参数训练,然后使用测试机检验训练结果,如果训练效果达标,则可使用训练出的数据应用于实际使用场景,对于神经网络其训练过程最为主要,以下我们主要阐述其训练方法。
对于图4中的神经网络模型,我们做如下定义:
- 给定训练集,即输入数据维度为,输出数据维度为。
- 图4中,假设神经网络是输入节点为个,输出节点为个,隐层有个的多层前向反馈神经网络,输出层第个神经元阈值为,第个隐层神经元阈值为.输入层第个节点与隐层第个节点之间的权重为,隐层第个节点与输出层第个节点的权重为.
根据以上假设可以有如下公式:
- 激活函数为
- 隐层第个神经元接收到的输入为
- 隐层第个神经元的输出为
- 输出层第个神经元接收到的输入为
- 输出层第个神经元的输出为
由以上5个公式可知,神经网络之中只要以下个参数确定,则就可以由输入计算出输出,这些参数分别为
- 输入层到隐层权重个,隐层到输出层权重个
- 隐层神经元阈值个,输出层神经元阈值个
那么我们如何得到这么多个参数呢?BP神经网络算法使用误差逆向传播进行训练。
2.2 BP神经网络的训练
神经网络的初始参数为内随机数,假设某次训练过程中神经网络的输入的某个训练数据为,经过神经网络的输出为,其中
6. 对于训练数据集中的单个数据其误差
我们采用梯度下降法根据误差对神经网络中的参数进行反馈学习,神经网络中参数更新的公式为,
此处以隐层到输入层权重为例对神经网络参数更新公式进行推导:
我们以误差的负梯度方向对参数进行更新,为学习率,有如下公式:
7. 参数更新公式
8. 参数调整力度
9. 注意到,先影响到第个输出神经元的输入值,再影响到其输出值, 根据偏导数的链式法则有
10. 根据的定义显然有
11. 由于sigmoid函数的导数具有特殊性质
12. 则
按照以上推导方法有
13.
14.
15. 同理,
16.
17. 在15.16式中,而影响个,又影响,所以有
注意在公式13.14.15.16中控制着每一轮迭代中的更新步长,若太大,则容易振荡,太小则学习过程收敛很慢,为了细微调节,13.14中的学习率可以和15.16中的不一样。
18. 使用训练集上的累积误差衡量训练质量
2.3 BP神经网络的训练过程
- 在内随机初始化神经网络中的连接权重和阈值;
- repeat
- for 遍历训练集中的每一个样本
- 根据当前参数按照公式1.2.3.4.5计算样本的与.
- 根据公式12.17计算与.
- 根据公式13.14.15.16更新.
- end for
- until (迭代若干次或者累积误差小于特定值)
- 得到BP神经网络的参数
3. C语言实现
C语言的实现就很简单了,BP神经网络分为两个部分:
1. 训练模块,包含训练以及验证过程,注意此神经网络的输入输出都需要预先进行归一化处理。
1 /** 2 * To fetch test_set. 3 * The length of in is IN_N, the length of out is OUT_N. 4 */ 5 typedef bool (*test_set_get_t)(double *in, double *out); 6 7 /** 8 * Reset test_set fetch process. 9 */ 10 typedef bool (*test_set_init_t)(void); 11 12 /** 13 * Init bpnn module. 14 */ 15 void bpnn_init(void); 16 17 /** 18 * Train bpnn module and produce parameter file. 19 * @param f_get To get test data in stream. 20 */ 21 void bpnn_train(test_set_get_t f_get, test_set_init_t f_init); 22 23 /** 24 * Test result of bpnn train parameter. 25 * @param f_get 26 */ 27 void bpnn_sim(test_set_get_t f_get);
2. 拟合模块;
#define T bpnn_t typedef struct T *T; /** * Init bpnn module. * @return */ T bpnn_fit_new(void); /** * Using bpnn fit in to out. * @param bpnn * @param in * @param out */ void bpnn_fit(T bpnn, double *in, double *out); /** * Uninit bpnn. * @param bpnn */ void bpnn_fit_free(T *bpnn);
详细的实现请访问github:,https://github.com/ThreeClassMrWang/c-bpnn
实现里教会了神经网络进行的计算,详细请见github,谢谢!
再次声明,这个文章是 知乎王小军 的,看原文请点击文章开头处的链接,可以关注下这位大佬在做什么,共同进步。