模板
python神经网络编程①-基于MNIST数据集
- 本人通过异步图书《python神经网络编程》这部书来学习,所以此博客内容大概为这本书的概括。
基础知识储备:
- 一台简单的预测机
- 计算机器神经元
- 在神经网络中追踪信号
1.一台简单的预测机
我们通过眼睛看到外边世界,然后通过大脑分析场景,继而思考分析场景得出结论。
对于一台基本的机器而言,接受了一个问题,做出一些“思考”,然后输出一个答案。如下图所示:
但是对于计算机而言,它并不是真正的思考,它只是一个经过包装的计算器,因此下面的流程更恰当:
一台计算机接受了一些输入,执行了一些计算,然后弹出输出结果。下面我们用简单的例子来引出神经网络的概念。
例子:试想一台将千米转化为英里的一台机器,如下图所示:
如果我们不知道英里与千米的转化关系,只知道两者是线性的,那么我们很容易想到:“英里=千米*C”,其中C为一个常量。现在如果告诉你一些千米/英里的匹配数据,那么我们怎么计算C呢?
真实示例 | 千米 | 英里 |
---|---|---|
1 | 0 | 0 |
2 | 100 | 62.137 |
这里对于机器来说,先给它一个C让它试一下,比如C=0.5:
这里机器给我们的答案是50英里,但是从上面列表中可以看到真实答案应该为62.137,因此我们知道这个输出结果是不准确的。
我们少了12.137,这是计算结果与我们列出的示例真实值之间的差值,是误差,即:
这一步我们既然知道了误差,那下一步我们可以利用这个误差,来更新我们的C值,指导我们得到第二个、更好的C的猜测值。
我们知道少了12.317,根据** 英里=千米*C **,我们知道增加C就可以增加输出,所以现在我们把C从0.5增加到0.6来试试看,此时输出值为60,这个答案的误差值为2.137,比C=0.5的时候要小很多了。
接下来如果我们继续增大C,企图接着减小误差误差值,我们将C=0.7,此时计算出来英里为70,但是此时误差变为了:-7.863,根据符号得知:我们此时不是不足,而是“超调”了。到这里可以看出,C=0.6的误差值要比C=0.7的误差值要好很多。我们就此可以结束这个练习,接受C=0.6带来的小小误差。其实我们接着还可以向前走一小段距离,比如用C=0.61代替C=0.6,我们得到输出值61,这次误差只有1.37,比刚才的还要小。
通过上述我们知道,通过适当调整C值,如果输出值越来越接近正确答案,即误差值越来越小,那么我们就不要做那么大的调整,使用这种方式,就可以避免像先前那样得到超调的结果。
实际上面我们做的就是大概浏览了一遍神经网络学习的核心过程,我们训练机器,使其输出值越来越接近正确的答案。我们可以思考一下这个过程,会发现这不像求解数学题那样算出精确答案,而是我们通过尝试得到一个答案,然后多次改进答案,这就是迭代的过程。
2.计算机器神经元
学过生物的同学都知道,虽然神经元有各种形式,但是所有的神经元都是将电信号从树突一端沿着轴突传输到树突端,然后这些信号从一个神经元传递到另一个神经元。这就是身体感知光、声、热等信号的机制。
下面我们来看一下一个神经元是怎么工作的。它接受一个电输入,输出另一个电信号。这和我们先前的机器模型一样,都是接收一个输入,然后进行一些处理,最后弹出一个输出。
实际上,神经元不会立即反应,而是会抑制输入,直到输入增强,强大到可以触发输出,也就是说,在产生输出之前,输入必须达到一个阈值。就像水在杯子里,直到水装满了杯子,才可能溢出。实际上这种机制可以抑制噪声的传播,从而只传递有意识地明显信号。
数学上有很多**函数可以达到上述的效果,比如阶跃函数。我们实际在使用时,用的是改进的阶跃函数,我们称之为S型函数。这个函数相对平滑,更自然、更接近现实。
虽然人工智能研究人员还使用其他外形类似的函数,但是S函数简单,并且事实上非常常见。S函数有时也称为逻辑函数:。
关于S函数就说到这,让我们回到神经元,思考如何建模人工神经网络。
首先我们要意识到生物神经元可以接受许多输入,而不仅仅是一个输入,每个神经元接受来自其之前多个神经元的输入,并且如果神经元被激发了,它也同时提供信号给更多的神经元。将这种自然形式复制到人造模型的一种方法是,构建多层神经元,每一层中的神经元都与其前后层的神经元互相连接。下图就描述了这种思想:
上图这种模型有三层神经元,每一层有三个人工神经元或结点。从此图还可以看到每个节点都与前一层或后续层的其他每一个节点互相连接。
对于这个体系架构,哪一部分能够执行学习功能呢?针对训练样本,我们应该如何调整做出反应呢?如何调整参数呢?
关于调节参数,最明显的一点就是调节节点之间的连接强度。在一个结点内,我们可以调整输入的总和或S阈值函数的形状,但是比起简单地调整节点之间的连接强度,调整S阈值函数的形状要相对复杂。
下图显示了连接的结点,但是这次在每个连接上显示了相关的权重。较小的权重将弱化信号,而较大的权重将放大信号。其中权重符号旁边的有趣小数字(即下标),简单说来,权重与前一层节点2传递给下一层的节点3的信号相关联。因此,权重减小或放大节点1传递给下一层节点2的信号。为了详细说明这种思路,下图突出显示了第一层与第二层之间的两条连接:
3.在神经网络中追踪信号
每个神经元都与其前后层的每个神经元相互连接的三层神经元图片看起来让人相当惊奇。但是,计算信号如何经过一层层的神经元,从输入变成输出,这个过程似乎有点令人生畏,这好像是一种非常艰苦的工作。但是这对说明神经网络如何工作非常重要,这样我们就可以知道神经网络内部发生了什么事情。因此我们尝试使用只有两层、每层两个神经元的较小的神经网络,来演示神经网络如何工作,如下图所示:
此时我们令两个输入值分别为:1.0和0.5。每个节点使用**函数,将输入变成输出。我们这里使用S函数:,其中神经元的输入总和为x,神经元输出为y。关于权重我们这里使用一些随机权重,令=0.9,=0.2,=0.3,=0.8。
在这个小型的神经网络中,由于连接每一层中两个节点的组合就只有四种连接方式,因此只有四种权重。
下面就可以开始计算了,第一层为输入层,仅表示输入信号,也就是说,输入节点不对输入值应用**函数。接下来的第二层,我们需要做一些计算。对于这一层的每个节点,我们需要算出组合输入。对于刚才的S函数而言,x就代表一个节点的组合输入。此处组合的是所连接的前一层中的原始输出,但是这些输出得到了链接权重的调节。下面这幅图就包括使用链接权重调节输入信号的过程:
我们首先关注第二层的节点1.第一层输入层中的两个节点连接到了这个节点。这些输入节点具有1.0和0.5的原始值。来自第一个结点的链接具有0.9的相关权重,来自第二个节点的链接具有0.3的权重。因此,组合经过了权重调节后的输入,如下所示:
$ x=(1.00.9)+(0.50.3)$
现在我们已经得到了x=1.05,这是第二层第一个节点的组合调节输入。最终,我们可以使用**函数计算该节点的输出,计算结果为:。因此,y=0.7408。
同理我们可以计算其他节点,最后计算结果如下图所示:
从一个非常简化的网络得到两个输出值,这个工作量相对较小。对于一个相对较大的网络,我们不希望用手计算,但是计算机对于计算不知疲倦,并且运算速度快,所以我们可以考虑用计算机编方法来计算程来进行计算。下一篇博客就介绍用简洁方法(矩阵)计算