【Python】搭建你的第一个简单的神经网络_准备篇_NN&DL学习笔记(二)

前言

本文为《Neural Network and Deep Learning》学习笔记(二),可以转载但请标明原文地址。

本人刚刚入门、笔记简陋不足、多有谬误,而原书精妙易懂、不长篇幅常有柳暗花明之处,故推荐阅读原书。

《Neural Network and Deep Learning》下载地址(中文版):Neural Network and Deep Learning(中文版)

注:这本书网上有很多免费版,随便搜一下就有了,不用非得花积分下载我上传的资料。


第二部分:准备篇(搭建神经网络、选择学习算法)

理论篇中,我们讲述了神经元与神经网络的基本知识,那么下面我们就来搭建一个神经网络吧!

本篇中依然不涉及代码部分,只讲解了一些前期准备过程,想要直接食用源码,可以跳到实践篇

我们将以【手写数字识别】项目为例进行讲解。

手写数字识别是指:输入一张图片,图片中包含一个数字,输出该数字是什么。

一、搭建一个三层神经网络

在理论篇中,我们讲到:神经网络的架构可以分为三部分:输入层、输出层、隐藏层。下面我们就来分别设计:

1.1 设计输入层(input layer)

输入图片,就相当于输入图片的每一个像素。因此我们设计的网络的输入层,必须包含给输入像素的值进行编码的神经元。

例如,在手写数字识别项目中,我们的输入图像来源于MNIST数据集,这些图像是28×28大小的灰度图像。这意味着我们的输入层需要包含784=28×28个输入神经元,值为0.0表示白色,值为1.0表示黑色,中间数值表示逐渐暗淡的灰色。

扫描二维码关注公众号,回复: 4195776 查看本文章

这样就完成了输入层的设计。

1.2 设计输出层(output layer)

我们需要的输出是:“判断输入图片是什么数字”,一共有0-9共十个数字,因此我们的输出神经元有10个,将它们按0-9编号。

接下来我们需要人为定义输出值的意义:如果编号为0的输出神经元被激活,那么表明输出是“数字0”;如果编号为1的输出神经元被激活,那么表明输出是“数字1”;以此类推。

这里出现了一个词:“激活”。还记得在理论篇中,我们曾经讲过激活函数吗?激活函数的作用在于:将神经元的输入(x)映射到输出(output),在这里我们将output称作激活值

我们共有10个输出神经元,每个神经元都有一个output,也就是说都有一个激活值。我们可以这样定义:哪个输出神经元输出的激活值最高,就证明网络判断哪个数字最有可能。

比如:10个输出神经元中,编号为0的神经元激活值最高,那么表明输出是“数字0”.

这样就完成了输出层的设计及输出值的解释定义。

1.3 设计隐藏层(hidden layer)

作者曰:设计隐藏层是一门艺(xuan)术(xue)。

简单起见,我们只设计一层隐藏层,假设该层中有n个隐藏神经元,我们将给n实验不同的数值,观察准确率的变化。

以上,三层神经网络设计完毕,网络拓扑图如下所示:

二、设计学习算法:梯度下降算法

神经网络、机器学习,到底是怎么学习的?!?!学习的到底是什么?!?!

2.1 学习是什么

让我们再来看看我们的激活函数(=S型函数)(=output的计算公式):

output=\sigma \left ( wx+b \right )=\frac{1}{1+e^{-wx-b}}=\frac{1}{1+exp\left ( -wx-b\right )}

其中:x是输入,output是输出,权重w和偏置b是我们引入的参数。

问题来了:对于随机输入一张图片x,如何使输出output的准确率更高呢?

答案是:不断调整参数w和b,使输出值向着准确率更高的方向发展。

这就是学习过程,学习内容就是参数w和b,学习目的就是让output准确率更高。

这就好比:我在蓝翔开挖掘机,需要铲一个鸡蛋起来,我一铲子下去往左偏了,那么下次我就往右调整一点,我一铲子下去力气大了,那么下次我就力气小一点。我就这么一次次调整参数,总有一天我能够一铲子下去就铲起鸡蛋,这时候我会说:我学习到了最佳下铲方向和最佳力气,现在我铲鸡蛋的准确率非常高。

当然,在神经网络中,我们不可能一次次运行神经网络然后根据结果手动调整参数,于是我们需要设计学习算法。

学习算法的作用:让网络自动调整权重w和偏置b,使模型向着准确率越来越高的方向发展。

在这里我们介绍一种学习算法:梯度下降算法。

2.2 MNIST数据集

我们先来介绍一下MNIST数据集,MNIST 数据分为两个部分:

第⼀部分包含 60,000 幅⽤于训练数据的图像。这些图像扫描⾃250人的⼿写样本,这些图像是28 × 28 ⼤⼩的灰度图像。

第⼆部分包含 10,000 幅⽤于测试数据的图像,同样是 28 × 28 的灰度图像,测试数据取⾃和训练数据不同的另外⼀组 250人。

我们可以把第一部分的 60,000 副图像再划分成两个部分:

① ⼀部分 50,000 个图像作为训练集,我们将⽤来训练我们的神经⽹络,使其学习参数w和b。

② 剩下的 10,000 个图像作为验证集,在本文中我们没有用到验证集,但在之后的学习中我们会发现,它对于设置某些超参数很有用 —— 例如学习速率等。

第二部分的 10,000 副图像作为测试集,我们将⽤这些测试数据来评估我们的神经⽹络准确性。

2.3 梯度下降算法

1、什么是代价函数/损失函数/loss

按照惯例,我们用x表示训练输入(训练集图像的输入),x是一个28×28=784维的向量,每个分量代表图像中单个像素的灰度值。

我们用y=y\left ( x \right )表示【输入x】对应的【期望输出y】,y是一个10维向量。

什么叫【期望输出】呢?说白了就是正确答案,比如:输入一张图片0,期望输出就是y\left ( x \right )=\left ( 1,0,0,0,0,0,0,0,0,0 \right )^{T},代表“只有编号为0的输出神经元被激活了”。

我们希望有一个学习w和b的算法,能够让我们的output与【期望输出y】无限接近……等等,如何判断output和【期望输出y】的接近程度?

我们定义一个代价函数(损失函数/loss)来描述:“对于不同的w和b,output和【期望输出y】的接近程度”

其中:w表示所有的网络中权重的集合,b是所有的偏置;

           x是输入,y(x)是对应x的期望输出(也就是正确答案),a是对应x的实际输出output;

           n是训练输入数据的个数。

整个函数的意思是:对每个输入x,计算一下期望值y和实际值a的差,平方后再求和,再除以2倍的总个数。

可以看出,C(w,b)≥0,而C(w,b)越接近0,证明期望值和实际值越接近,证明我们的神经网络准确率越高!

我们把C称为二次代价函数,有时也称为均方误差MSE

到现在,我们的学习算法目的已经非常明确了:找到合适的w和b,让C越小越好!

2、梯度下降算法

终于到正题了,再重复一遍,我们训练神经网络的目的是,找到权重w和偏置b,最小化二次代价函数 C(w,b) 。

2.1 第一个目的:找到w和b,最小化C(w,b)

我们需要使用梯度下降算法来达到这个目的,这里需要一些导数的知识。

显然,C是一个具有两个变量的函数,我们给这两个变量换个名字,v1和v2,那么函数图像如下所示:

我们的目的现在变成:找到变量v1和v2,使函数C取最小值(尽量最小)。

2.2 第二个目的:找到变量v1和v2,最小化C(v1,v2)

梯度下降算法的思想是:把我们的函数C想象成一个坑,假设把一个小球随机放在某个位置,那么小球总是会向低处滚,最终到达坑底。

这个过程的关键在于:“向低处滚”如何实现?

小球的位置可以用(v1,v2)描述,我们先来看看,当小球随便移动时,函数C的值会有什么变化:

(公式1)

这个公式的意思是:

假设小球原位置在(v1,v2),此时函数值是C;我们把小球移动到(v1*,v2*),此时函数值是C*;

令ΔC=C*-C;Δv1=v1*-v1;Δv2=v2*-v2;那么我们可以通过Δv1和Δv2计算出ΔC,其中Δv1和Δv2的参数是偏导数,可以看作常量。

我们当然希望:小球每次移动,C越来越小,也就是C*<C,也就是ΔC<0。

我们的目的现在变成:选择Δv1和Δv2,使ΔC<0

2.3 第三个目的:选择Δv1和Δv2,使ΔC<0

2.3.1 简化公式

我们需要将上面那个(公式1)简化一下(就像简化激活函数的公式那样):

① 定义Δv为v变化的变量:

② 定义\triangledown C,给它起个名字叫做梯度向量:

那么上面那个(公式1)就简化成下面这样:

(公式2)

2.3.2 分析公式2

在(公式2)中,我们可以得到下面两个信息:

① 梯度向量\triangledown C的作用在于:对于v的变化,计算得到C的变化,就好像一个梯子把它们关联起来,这就是被称为“梯度向量”的原因。

② 我们的目的可以实现了!我们可以这么选取Δv,使ΔC<0:

(规则1)

看上去是不是很简单呢?代入上面那个公式2,就变成:

\triangle C\approx -\eta \cdot \left \| \triangledown C \right \|^{2}(公式3)

其中, \eta 是个很小的正数,我们把它叫做学习速率

又因为 \left \| \triangledown C \right \|^{2} 肯定大于0,所以这样计算得到的\triangle C肯定小于0.

目标达成!

2.3.3 具体怎么做呢?

挺过了公式推导,实现就简单许多啦,我们只需要每次这样做:

① 计算一下梯度向量\triangledown C

② 根据(规则1)计算一下\triangle v

③ 表明:根据\triangle v就可以得到v1和v2的变化。

所以,只要一直迭代上面三步,\triangle C一直小于0,C就会越来越小、越来越小……

直到C已经不再减小,我们就得到了最好的v1和v2(就算不是最好,也是相当好的)。

总结一下,梯度下降算法工作的方式就是重复计算梯度 ∇C,然后让小球沿着相反的⽅向移动,沿着坑底“滚落”。我们可以想象它像这样:

当然,求最小值的方法不仅仅有梯度下降法这一种,但有观点认为这是最佳策略。理由在于:梯度下降法是在C下降最快的方向上,每次做微小移动。

2.3.4 学习速率\eta

在开心之余不要忘了还有一个问题:超参数【学习速率\eta】该如何设置呢?

一方面,\eta越小,我们越能够逐步逼近全局最低值,(公式2)的近似度越好;

另一方面,\eta太小的话,梯度下降算法又非常缓慢。

在真正的实践中,\eta通常是变化的,使近似度和速度得到折中。

我们将在实践篇了解,设置不同的\eta,对于准确率的影响有多么巨大。

2.3.4 道理我都懂,但我们最初的目标:w和b怎么没出现呢?

我们需要把上面的梯度下降算法应用到我们的神经网络中:

那么,C(v1,v2)对应神经网络中的C(w,b);

(规则1)对应神经网络中的:

\triangle w=-\eta \cdot \frac{\partial C}{\partial w}

\triangle b=-\eta \cdot \frac{\partial C}{\partial b}(规则2)

假设w和b是原参数,w*和b*是新参数,那么新参数计算公式如下:

w*=w-\eta \cdot \frac{\partial C}{\partial w}

b*=b-\eta \cdot \frac{\partial C}{\partial b}  (公式4)

运用(公式4)来不断更新我们的w和b,就可以让神经网络学习了。

2.4 随机梯度下降算法

梯度下降算法的缺点在于:需要计算\triangledown C,变量增多,计算量成平方倍的增大,导致学习时间增大,令人难以忍受。

因而出现了许多替代算法,随机梯度下降就是一种加速学习的算法。

其思想在于:通过随机选取小量训练输入样本来计算\triangledown C_{x},进而估算\triangledown C,减少计算量。

更准确地说,我们随机选取小量的m个训练输入,标记为X1,X2,……,Xm,把它们称为小批量数据。

假设m足够大,我们可以用\triangledown C_{m}的平均值来估算\triangledown C

而迭代公式也变成了下面这样:

w*=w-\frac{\eta}{m} \cdot \frac{\partial C}{\partial w}

b*=b-\frac{\eta}{m} \cdot \frac{\partial C}{\partial b}

直到我们用完了所有的训练输入,被称为完成了一个训练迭代期。然后我们就会开始新一个迭代期。

需要注意的是,这相当于学习速率从 \eta 变成了 \frac{\eta}{m}

实践证明,随机梯度下降算法能够千倍加速学习过程。

神经网络架构已经设计好,学习算法也已经选好,下一步,就该写代码了。实践篇,敬请期待。


【2018/11/19后记】

1、我真的疯了,今天下午看到访问量1w+,新建一篇博客就开始码字,全然不顾我还有一门考试、两个报告、一个大作业、两篇论文、一个项目要做……对CSDN真的是呕心沥血、真情实感了。

2、这篇从下午到晚上码了将近三个小时,饭没吃,晚课差点迟到,本来想一鼓作气把实践篇写完,结果越写越多、越写越多,只能临时加了个准备篇,实践篇争取今晚写完,然后就真的要专心准备报告和考试了!!!立个flag,下周二之前不上博客了!!!

3、第一次写学习笔记,很粗糙,图都是截自原书,有的公式懒得写也直接截图了,毕竟这种超级入门级的东西大概也没多少人看,全理论也很难钻研,我的讲述又肯定比原书差一万倍orz,只能聊以自慰吧,毕竟整理出来是真的很开心,感觉也收获了很多。

猜你喜欢

转载自blog.csdn.net/qq_41727666/article/details/84255469