python-神经网络编程笔记摘要第一章

书名--《Python 神经网络编程》中文版,英文版《Make Your Own Neural Network》,全书都是彩色的,花了2天的时间把这本书刷完了,总的感觉内容浅显易懂,非常适合新手阅读,讲解的内容也比较集中,大致内容解释了简单的三层神经网络是如何计算的,如何使用矩阵进行计算,并且使用IPython进行了编程实现,内容中没有深奥的理论基础要求,有一点数学知识就可以上手,讲解的非常清楚,下面对该书的主要内容点进行了梳理,方便自己以后回看。

第一章:神经网络是如何工作的?

这一章主要从一个简单的线性分类器开始,构建了一个有输入,有线性函数,有输出的简单分类预测模型,其实它的原理和神经网络相似,都是通过一个输入,经过内部函数的计算,得到一个输出,我们完成的工作就是给内部的函数的参数赋初值,并且通过计算得到的输出与最终的输出比较,得到误差,通过误差来指导函数中参数的修正,使得参数的调整不断的使误差减小,利用数据反复的修正参数,这是一种迭代的,持续细化误差的思想,直到误差减小到一个可以接受的范围内,就完成了训练。

python-神经网络编程笔记摘要第一章

最简单的工作原理

对于学习率的理解:如果每次都按照当前的误差去修正参数,那么最后获得参数就是和最后一次训练的数据有关,和之前训练的数据没有关系,因此,可以使得每次修正误差的时候,只是向着误差减小的方向修正,而不是直接修正到训练数据的地方。

举个例子:

线性函数    y=Ax    ;调整参数A之后得到的预测值为    t=(A+△A)x    ,最后的误差是    E=t-y=△Ax    ,需要修改的参数就是E/x;也就是直接将参数修正到了此时的训练数据中。结果与之前使用的数据没有了关系,也就是说最后的到修正过的A只适用于最后一组数据。

**函数的理解:设计来源于人的神经细胞的神经元,每个神经元在接受信号之后,不是立刻有反应,而是当输入信号的强度达到一定的阈值的时候,才有输出,即神经元不希望传递微小的噪声信号,只有足够强的信号才能被传递,**函数就是完成了这么一个阈值限定的作用。如下图所示,最常用的**函数:sigmoid函数:

python-神经网络编程笔记摘要第一章python-神经网络编程笔记摘要第一章

sigmoid函数

  • 神经网络模型的理解:由于线性函数过于简单,只能针对线性可分的情况,对于线性不可分的关系,没有办法处理,因此使用多个线性函数的组合来解决。人体的每个神经元在工作的时候,都接受来自其他多个神经元的信号,并且将自己的信号传递给其他神经元,也就是每个神经元的输入都是一个有多输入的线性函数,如下图所示:第一层的神经元为输入神经元,第二层的每个神经元接受前一层的所有神经元的信号输入,输出层的每一个神经元接受前一层所有神经元的输入,同时每一个神经元最后的输出还有经过一个**函数,对微弱的信号进行抑制,这种模型就和人的神经系统比较相似了。我们所要做的就是通过最后的误差来指导我们修改所有神经元对应的权重,也就是前面提到的A的值。

python-神经网络编程笔记摘要第一章

人体神经网络模型

  python-神经网络编程笔记摘要第一章

单个神经元的模型

python-神经网络编程笔记摘要第一章

三层的神经网络模型(与人的神经网络模型相似)

  • 使用矩阵来表示信号的传递:考虑只有两层的网络,一个输入层n个神经元,一个输出层m个神经元,输入是一个n*1的向量,我们希望得到的是一个m*1的向量,对于参数的数量,因为每个输出的神经元都由输入的神经元线性组合成,所以,参数有m*n个,很容易想到矩阵相乘-----(m*n)*(n*1)=(m*1),即w*I=O(w为参数矩阵,I为输入,O为输出)。具体参数的见下图:

python-神经网络编程笔记摘要第一章

两层的网络模型

python-神经网络编程笔记摘要第一章

python-神经网络编程笔记摘要第一章

使用矩阵计算表示网络

  • 误差的反向传播:我们先考虑只有两层的神经网络,非常容易想到,最后一层输出的是最终的结果,我们有label数据,因此最后一层的误差可以直接使用二者相减获得,考虑如何获得前一层的误差,简单的就是平均分配误差,另外一种就是根据链接权重大小按照比例不同分配误差。书中采用后者,应该是因为权重的大小不同代表了对结果的影响的大小,因此误差的来源也应该有不同的比重。具体见下图:

python-神经网络编程笔记摘要第一章

误差的反向传播

    如上图,layer1中的每个节点的误差来源由layer2误差的线性组合获得,这样的话,同样也可以通过矩阵计算,由layer2的误差获得layer1的误差。计算的过程中忽略了分母,简化表达如下。

  python-神经网络编程笔记摘要第一章

误差反向传播的矩阵表示

    与前面的参数矩阵相比较,此处的矩阵刚好是前馈网络参数的转置,因此获得误差反向传播的公式:

   python-神经网络编程笔记摘要第一章

误差反向传播公式

  • 权重的更新:通过上面,我们可以计算得到每一层的误差,接下来就要使用获得的误差来指导权重的更新。

如果我们采用暴力的方法去更新权重,也就是所有权重的组合,对于3层的网络,每个层有3个节点,权重有18个,假设每个权重在(+1,-1)之间,学习率为0.001,那么所有的可能有18000种,如果有每层500节点,有5亿种可能性,每种情况用1s,那么需要16年去更新参数·····因此不能使用这种方法更新参数;

如果我们采用暴力的方法去更新权重,也就是所有权重的组合,对于3层的网络,每个层有3个节点,权重有18个,假设每个权重在(+1,-1)之间,学习率为0.001,那么所有的可能有18000种,如果有每层500节点,有5亿种可能性,每种情况用1s,那么需要16年去更新参数·····因此不能使用这种方法更新参数;

如果我们每次都向着误差减小的方向更新参数,最后肯定可以获得一个局部极小的结果,在数学上就是梯度下降法,使用学习率,采用步进的思想,一点一点的靠近我们想要的结果。最后的结果不一定是最小值,可以通过多次采用不同的起点和学习率等来获得很多结果,最终肯定可以获得最小值,使用二维函数表示如下图:

python-神经网络编程笔记摘要第一章

权重更新思想

误差函数的选择:使用平方误差最为误差函数,原因如下:

1、容易计算出梯度下降的方向,即容易求导

2、误差函数连续平滑,没有间断和突然跳跃

3、越接近最小值,梯度变化越小,超调的风险减小

最终的参数更新公式如下:

python-神经网络编程笔记摘要第一章

E是误差,Wjk表示输入层j节点与输出层k节点之间的权重;下面进行求导的计算:

    python-神经网络编程笔记摘要第一章

    python-神经网络编程笔记摘要第一章

上图是自己写的误差梯度计算的推到(初学者,有错希望指出谢谢,详细的可以参考原书),最后得到的核心公式为:

python-神经网络编程笔记摘要第一章

Ek为输出层的误差,Ok为输出,Oj为输入,接下来使用矩阵进行表示:

python-神经网络编程笔记摘要第一章

这样的话,可以很轻松的根据误差完成权重的更新!~

  • 数据的准备:    

到现在,已经完成了一个简单的神经网络和如何进行训练更新权重,还要对输入和输出的数据进行处理,才能使用神经网络的模型。对于输入,因为如果输入过大的话,经过sigmoid函数,计算出该点的梯度非常的小,对于训练非常不利,网络会接近饱和。因此可以将输入转换到(0,1)的范围内,但是当输入为0的时候,在计算梯度的时候,公式中有一项是输入,如果输入为0,会导致梯度消失,因此将输入缩放到(0.01,1)的范围当中。

对于输出因为最后的输出经过**函数,**函数值域范围是(0,1)之间,因此我们的目标也应该是(0,1)之间,由于函数无法取到0,1,所以输出的目标应该是(0.01,0.99)之间。

对于权重的初始化,因为大权重会造成大的信号输入**函数,造成网络的饱和,因此权重的范围应该为(-1.0,1.0)之间,需要注意的地方是,不可以将权重设置为一样,特别是0,如果这样做,每个节点都将接收到想听的信号,输出的值也想同,误差反向传播的时候误差会平分,权重会进行相同的变化,更新后的权重又是相同的,如此循环,可想而知。

  • 总结

对于一个简单的神经网络,首先我们定义网络的规模,即输入的节点数,隐层的节点数,输出的节点数,学习率,然后初始化权重,使用矩阵的计算,可以计算的网络正向传播的输出值,然后通过反向传播计算误差的传递,最后通过误差指导权重的更新,这样就可以简单的构建一个神经网络。

核心公式汇总如下:

python-神经网络编程笔记摘要第一章

python-神经网络编程笔记摘要第一章

python-神经网络编程笔记摘要第一章

python-神经网络编程笔记摘要第一章

在第二章中,讲解了如何利用上面得到的公式使用python写一个自己的神经网络,并且使用mnist手写数字体完成训练和测试。(有写的不正确的地方,还请指出,谢谢~~)

注:图片公式均来自Make Your Own Neural Network。