前言
本文为《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表示黑色,中间数值表示逐渐暗淡的灰色。
这样就完成了输入层的设计。
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的计算公式):
其中: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维的向量,每个分量代表图像中单个像素的灰度值。
我们用表示【输入x】对应的【期望输出y】,y是一个10维向量。
什么叫【期望输出】呢?说白了就是正确答案,比如:输入一张图片0,期望输出就是,代表“只有编号为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变化的变量:
② 定义,给它起个名字叫做梯度向量:
那么上面那个(公式1)就简化成下面这样:
(公式2)
2.3.2 分析公式2
在(公式2)中,我们可以得到下面两个信息:
① 梯度向量的作用在于:对于v的变化,计算得到C的变化,就好像一个梯子把它们关联起来,这就是被称为“梯度向量”的原因。
② 我们的目的可以实现了!我们可以这么选取Δv,使ΔC<0:
(规则1)
看上去是不是很简单呢?代入上面那个公式2,就变成:
(公式3)
其中, 是个很小的正数,我们把它叫做学习速率。
又因为 肯定大于0,所以这样计算得到的肯定小于0.
目标达成!
2.3.3 具体怎么做呢?
挺过了公式推导,实现就简单许多啦,我们只需要每次这样做:
① 计算一下梯度向量
② 根据(规则1)计算一下
③ 表明:根据就可以得到v1和v2的变化。
所以,只要一直迭代上面三步,一直小于0,C就会越来越小、越来越小……
直到C已经不再减小,我们就得到了最好的v1和v2(就算不是最好,也是相当好的)。
总结一下,梯度下降算法工作的方式就是重复计算梯度 ∇C,然后让小球沿着相反的⽅向移动,沿着坑底“滚落”。我们可以想象它像这样:
当然,求最小值的方法不仅仅有梯度下降法这一种,但有观点认为这是最佳策略。理由在于:梯度下降法是在C下降最快的方向上,每次做微小移动。
2.3.4 学习速率
在开心之余不要忘了还有一个问题:超参数【学习速率】该如何设置呢?
一方面,越小,我们越能够逐步逼近全局最低值,(公式2)的近似度越好;
另一方面,太小的话,梯度下降算法又非常缓慢。
在真正的实践中,通常是变化的,使近似度和速度得到折中。
我们将在实践篇了解,设置不同的,对于准确率的影响有多么巨大。
2.3.4 道理我都懂,但我们最初的目标:w和b怎么没出现呢?
我们需要把上面的梯度下降算法应用到我们的神经网络中:
那么,C(v1,v2)对应神经网络中的C(w,b);
(规则1)对应神经网络中的:
(规则2)
假设w和b是原参数,w*和b*是新参数,那么新参数计算公式如下:
(公式4)
运用(公式4)来不断更新我们的w和b,就可以让神经网络学习了。
2.4 随机梯度下降算法
梯度下降算法的缺点在于:需要计算,变量增多,计算量成平方倍的增大,导致学习时间增大,令人难以忍受。
因而出现了许多替代算法,随机梯度下降就是一种加速学习的算法。
其思想在于:通过随机选取小量训练输入样本来计算,进而估算,减少计算量。
更准确地说,我们随机选取小量的m个训练输入,标记为X1,X2,……,Xm,把它们称为小批量数据。
假设m足够大,我们可以用的平均值来估算。
而迭代公式也变成了下面这样:
直到我们用完了所有的训练输入,被称为完成了一个训练迭代期。然后我们就会开始新一个迭代期。
需要注意的是,这相当于学习速率从 变成了 。
实践证明,随机梯度下降算法能够千倍加速学习过程。
神经网络架构已经设计好,学习算法也已经选好,下一步,就该写代码了。实践篇,敬请期待。
【2018/11/19后记】
1、我真的疯了,今天下午看到访问量1w+,新建一篇博客就开始码字,全然不顾我还有一门考试、两个报告、一个大作业、两篇论文、一个项目要做……对CSDN真的是呕心沥血、真情实感了。
2、这篇从下午到晚上码了将近三个小时,饭没吃,晚课差点迟到,本来想一鼓作气把实践篇写完,结果越写越多、越写越多,只能临时加了个准备篇,实践篇争取今晚写完,然后就真的要专心准备报告和考试了!!!立个flag,下周二之前不上博客了!!!
3、第一次写学习笔记,很粗糙,图都是截自原书,有的公式懒得写也直接截图了,毕竟这种超级入门级的东西大概也没多少人看,全理论也很难钻研,我的讲述又肯定比原书差一万倍orz,只能聊以自慰吧,毕竟整理出来是真的很开心,感觉也收获了很多。