自己动手从零搭建神经网络

简书博客地址:https://www.jianshu.com/p/388bbb5e0245

入门

首先,先简单的讲解一下神经网络。
我们从构建超级简单的机器开始。有一台基本的机器,接受了一个问题,做了一些“思考”,并输出了一个答案。就像我们从眼睛输入图片,使用大脑分析场景,并得出在场景中有哪些物体的结论。

在这里插入图片描述

试想一下将千米转化为英里的一台机器,如下图所示。我们所知道的就是,两者之间的关系是线性的。这意味着,如果英里数加倍,那么表示相同距离的千米数也是加倍的。千米和英里之间的这种线性关系,为我们提供了这种神秘计算的线索,即它的形式应该是“英里=千米×C”,其中C为常数。现在,我们还不知道这个常数C是多少。

首先,我们从尝试使用C=0.5,带入机器计算出结果。

在这里插入图片描述

结果比实际值少了12.137。这是计算结果与我们列出的示例真实值之间的差值,是误差。即:
误差值=真实值-计算值
=62.137-50
=12.137

让我们将C从0.5稍微增加到0.6,再次进行计算。
现在,由于将C设置为0.6,我们得到了英里=千米×C=100×0.6=60,这个答案比先前50的答案更好。我们取得了明显的进步。

在这里插入图片描述

让我们再次重复这个过程。输出值60还是太小了。我们再次微调C,将其从0.6调到0.7。结果超过了已知的正确答案。先前的误差值为2.137,现在的误差值为-7.863。我们为什么不使用一个较小的量,微调C,将C从0.6调到0.61呢?

这比先前得到的答案要好得多。我们得到输出值61,比起正确答案62.137,这只差了1.137。
因此,最后的这次尝试告诉我们,应该适度调整C值。如果输出值越来越接近正确答案,即误差值越来越小,那么我们就不要做那么大的调整。使用这种方式,我们就可以避免像先前那样得到超调的结果。

再换个例子,简单分析一下,比如我们希望训练线性分类器,使其能够正确分类瓢虫或毛虫。下图并不能准确的区分瓢虫和毛虫。

在这里插入图片描述

我们尝试修改直线的斜率,这样我们就可以精确的区分出这两种小虫。那如何使用公式进行表达呢?
在这里插入图片描述

回顾一下,在千米转换为英里预测器的实例中,我们有一个调整了参数的线性函数。此处,由于分界线是一条直线,因此我们也可以进行相同的处理:
y=Ax
由于严格来说,此处的直线不是一台预测器,因此我们有意使用名称y和x,而不使用名称长度和宽度。与先前我们将千米转换为英里不一样,这条直线不将宽度转换为长度。相反,它是一条分界线,是一台分类器。
同样,我们也可以采用之前的方法,根据误差来对直线进行调整,对此不再赘述。

在这里插入图片描述

神经网络介绍

前面简单的介绍了线性分类器,下面开始正式介绍神经网络。神经网络是机器学习中的一种模型,是一种模仿动物神经网络行为特征,进行分布式并行信息处理的算法数学模型。这种网络依靠系统的复杂程度,通过调整内部大量节点之间相互连接的关系,从而达到处理信息的目的。下图就是一个简单的神经网络。

在这里插入图片描述

神经元

神经元是神经网络中最基本的结构,也可以说是神经网络的基本单元,它的设计灵感完全来源于生物学上神经元的信息传播机制。我们学过生物的同学都知道,神经元有两种状态:兴奋和抑制。一般情况下,大多数的神经元是处于抑制状态,但是一旦某个神经元收到刺激,导致它的电位超过一个阈值,那么这个神经元就会被激活,处于“兴奋”状态,进而向其他的神经元传播化学物质(其实就是信息)。神经元是神经网络中最基本的结构,也可以说是神经网络的基本单元,它的设计灵感完全来源于生物学上神经元的信息传播机制。我们学过生物的同学都知道,神经元有两种状态:兴奋和抑制。一般情况下,大多数的神经元是处于抑制状态,但是一旦某个神经元收到刺激,导致它的电位超过一个阈值,那么这个神经元就会被激活,处于“兴奋”状态,进而向其他的神经元传播化学物质(其实就是信息)。

神经元的输出需要使用激活函数,我们更常用的方法是用sigmoid函数来表示激活函数。sigmoid函数的表达式和分布图如下所示:
在这里插入图片描述

(现在通常使用的是ReLU,人们起初并不觉得它的效果会好过 sigmoid 和 tanh。但是,实战中它确实做到了。)

前向传播

神经网络是一种多层的前馈神经网络,其主要的特点是:信号是前向传播的,而误差是反向传播的。
假设从左面一层结点i,j,k,…等一些结点与本层的结点w有连接,那么结点w的值怎么算呢?就是通过上一层的i,j,k等结点以及对应的连接权值进行加权和运算,最终结果再加上一个偏置项,最后在通过一个非线性函数(即激活函数),如ReLu,sigmoid等函数,最后得到的结果就是本层结点w的输出。
最终不断的通过这种方法一层层的运算,得到输出层结果。

矢量化

先前,我们手工对两层、每一层只有两节点的神经网络进行计算。对人类而言,这样的工作量也是足够大了,但是如果要对五层、每层100个节点的网络进行相同的计算,单单是写下所有必要的计算,也是一个艰巨的任务……对每一层每一个节点,计算所有这些组合信号的组合,乘以正确的权重,应用S激活函数……
那么,矩阵如何帮助我们简化计算呢?其实,矩阵在两个方面帮助了我们。首先,矩阵允许我们压缩所有这些计算,把它们变成一种非常简单的缩写形式。由于人类不擅长于做大量枯燥的工作,而且也很容易出错,因此矩阵对人类帮助很大。第二个好处是,许多计算机编程语言理解如何与矩阵一起工作,计算机编程语言能够认识到实际的工作是重复性的,因此能够高效高速地进行计算。
总之,矩阵允许我们简洁、方便地表示我们所需的工作,同时计算机可以快速高效地完成计算。

神经网络中的误差

先前,我们通过调整节点线性函数的斜率参数,来调整简单的线性分类器。我们使用误差值,也就是节点生成了答案与所知正确答案之间的差值,引导我们进行调整。实践证明,误差与所必须进行的斜率调整量之间的关系非常简单,调整过程非常容易。
当输出和误差是多个节点共同作用的结果时,我们如何更新链接权重呢?下图详细阐释了这个问题。

在这里插入图片描述

反向传播

在这里插入图片描述

在这里插入图片描述

神经网络的运作过程如下。

  1. 确定输入和输出
  2. 找到一种或多种算法,可以从输入得到输出
  3. 找到一组已知答案的数据集,用来训练模型,估算w和b
  4. 一旦新的数据产生,输入模型,就可以得到结果,同时对w和b进行校正

通过反向传播把误差传播到每一层,但是怎么调整权重w
使用数学公式计算,解数学方程特别复杂
暴力枚举,当数据量过大时不可行
这时就需要使用梯度下降

梯度下降

简单的公式计算如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

## 深度学习

深度学习(DeepLearning)的概念由Hinton等人于2006年提出。此外Lecun等人提出的卷积神经网络是第一个真正多层结构学习算法,它利用空间相对关系减少参数数目以提高训练性能。深度学习(DL)是机器学习中一种基于对数据进行表征学习的方法,是一种能够模拟出人脑的神经结构的机器学习方法。(PS:两位大牛因为对深度学习的巨大贡献,因此获得2018年图灵奖)

说白了就是,深度学习就是深层的神经网络,比上面介绍的三层神经网络要复杂的多。

深度学习研究的热潮持续高涨,各种开源深度学习框架也层出不穷,其中包括TensorFlow、Caffe、Keras、CNTK、Torch7、MXNet、Leaf、Theano、DeepLearning4、Lasagne、Neon,等等。但是上图所示的简单的三层神经网络不需要使用任何深度学习框架,可以通过简单的 Python 代码就可以实现,下面主要讲一下实现过程。

Python实现

激动人心的时刻到了,下面直接使用Python代码,实现简单的神经网络。代码的主要框架如下:


# neural network class definition      

class neuralNetwork :     

     # initialise the neural network     

     def __init__() :pass       

    # train the neural network          

    def train() :pass      

    # query the neural network      

    def query() :pass

· 初始化函数—设定输入层节点、隐藏层节点和输出层节点的数量。

· 训练—学习给定训练集样本后,优化权重。

· 查询—给定输入,从输出节点给出答案。

实现的内容为识别mnist库中的手写数字,完整的代码如下:

https://github.com/makeyourownneuralnetwork/makeyourownneuralnetwork

可以查看 part2_neural_network.ipynb ,如果想训练自己手写的图片,可以看part3部分的代码,另外为了增加数据集,也可以对mnist中的图片进行旋转等操作。

向后查询

最后做个有意思的事情,在通常情况下,我们馈送给已受训练的神经网络一个问题,神经网络弹出一个答案。在我们的例子中,这个问题是人类的手写数字图像。答案是表示数字0到9中的某个标签。

如果将这种方式反转,向后操作,会发生什么呢?如果馈送一个标签到输出节点,通过已受训练的网络反向输入信号,直到输入节点弹出一个图像,那会怎么样?下图显示了正常的正向查询和疯狂的反向向后查询的想法。

逻辑S函数接受了任何数值,输出0和1之间的某个值,但是不包括0和1本身。逆函数必须接受相同的范围0和1之间的某个值,不包括0和1,弹出任何正值或负值。为了实现这一目标,我们将输入层重新调整到有效范围,选择的范围为0.01至0.99。

在这里插入图片描述

标签0的结果,从图中可以隐约的看到数字0

在这里插入图片描述

上图表示了从0-9的结果,是不是有点理解神经网络了呢?

主要参考《python神经网络编程》,感谢作者的讲解。

在这里插入图片描述

  • 25
    点赞
  • 114
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值