你能够在这里阅读 上一篇html
我是薛银亮,感谢英文原版在线书籍,这是我学习机器学习过程当中感受很是适合新手入门的一本书。鉴于知识分享的精神,我但愿能将其翻译过来,并分享给全部想了解机器学习的人,本人翻译水平有限,欢迎读者提出问题和发现错误,更欢迎大牛的指导。由于篇幅较长,文章将会分为多个部分进行,感兴趣的能够关注个人文集,文章会持续更新。git
人类的视觉系统是世界上最美妙的系统之一。来看一下下面的手写字:程序员
大多数人都能很容易识别出来是这些数字是:504192。在咱们的每个大脑半球,都有一个视觉皮层,也被称做V1,它包含1.4亿个神经元,在他们之间有数以百亿级的联系。并且不光有V1,一个完整的视觉皮层还有V二、V三、V4和V5,用来处理更加复杂的图像。这就比如咱们的大脑中有一台通过几百万年进化的超级计算机,用它很是适合理解世界的景象。识别手写字是很是困难的,可是咱们人类却能很轻松的作到,并且这些全部的工做彷佛也是在无心识的状况下被执行完成的,因此咱们一般都不会意识到咱们的视觉系统是在处理多么复杂的问题。算法
若是你尝试写一个计算机程序来识别像上面那种数字的话,看起来很简单可是在咱们动手作的时候去发现忽然变得异常的困难。就像上面的数字9,有一个圈在顶部,和右下部的一竖。当你尝试定制这样的程序规则来识别这个9的时候,你可能会很快迷失在各类特殊状况和意外处理等的沼泽中(缘由是基本每一个人写的9都是不同的),这看起来是没有但愿的。微信
然而,神经网络处理这个问题是使用不一样的方法: 使用大量的手写数字做为训练集合,就像下面这样的:网络
而后开发一个系统,让它从这个训练集中学习。换句话说,就是神经网络使用这些例子来自动推断手写数字的规则(就像上面的9那样的规则)。此外,经过增长训练集的数量,让网络学习更多的手写字,来提升它的准确性。上面的图中咱们仅仅展现了100个训练数字,可是或许咱们须要成千上万或者上百万个数字来训练咱们的网络才能创建更出色的手写字识别系统。机器学习
在这个章节咱们会写一个计算机程序来实现一个神经网络,并用它来学习手写数字。这个程序仅仅74行代码,而且不使用特殊的神经网络库。这个程序能在没有人为干预的状况下识别手写数字,其准确率超过96%。另外,在后面的章节咱们将会开发出将精度提升到99%的程序。实际上,如今有一些很好的商业用途的神经网络例子,如银行识别支票、邮局识别地址等。函数
咱们选择识别手写字的例子是由于它在学习机器学习的时候是一个杰出的例子原型,这个例子有一个优势:识别手写字是一个挑战,可是它却没有使用极其复杂的解决方案和巨大的计算能力。另外,深度学习是一个更佳高级的开发技术。因此在这个系列的文章中咱们会常常回顾识别手写字的问题。在后面,咱们会讨论如何将这些知识应用在其余的领域,如计算机视觉、语音识别等。工具
固然,若是这里仅仅写计算机识别手写字的话,那么内容或许会显得有点少!因此咱们将讨论不少关于神经网络的知识,包括两种重要的人工神经元(感知器和sigmoid 神经元),标准的神经网络学习算法是随机梯度降低算法。在这整个过程当中,我将注重解释下神经网络的原理并给你创建神经网络的概念。这就须要花费很长的篇幅来讨论,可是为了更深层次的理解这是值得的。在本章结束的时候,你能学习到什么是深度学习已经它的重要性。学习
什么是神经网络?首先,我将介绍一种人工神经元叫感知器(perceptron)。它是被科学家 Frank Rosenblatt 在1950年和1960年发明的。可是在工做中更经常使用的是另一种人工神经元,叫 sigmoid neuron。咱们会很快的了解到sigmoid神经元,但在这以前,为了了解为何sigmoid神经元被设计成它的样式,先花点时间学习perceptrons是很是有必要的。
Perceptrons是如何工做的呢?一个perceptron须要几个二进制输入,x1,x2,…,而且产生一个二进制的输出:
这个例子展现的perceptron有三个输入,x1,x2,x3。但通常它会有更多或者更少的输入。Rosenblatt(那个科学家的名字)设计了简单的规则来计算输出。他 引入了权重 w1,w2,…,这些值表明了每一个输入对输出产生影响的程度大小,也就是表明了每一个输入的重要性。这个神经元的输出结果是1或者0,其结果取决于输入的全部和
这就是一个perceptron工做的方式了。
这是一个基本的数学模型。你能够认为perceptron是一种经过权衡输入数据来作决定的装置。让我举个不是特别恰当的例子,可是很是容易理解,而且后面我会举出更加恰当的例子。假设周末的时候,你的城市将会有一个奶酪节日。你喜欢奶酪,并且正在考虑要不要去参加这个节日,你可能经过三个因素来作出这个决定:
咱们能够用三个二进制变量 x一、x2 和x3来表示这三个影响因素。例如,若是天气好,咱们有x1 = 1,若是天气很差,x1 = 0。 一样,若是你的男友或女友想去,x2 = 1,若是不是x2 = 0。 对于x3和公共交通也一样如此。
如今,假设你超级喜欢奶酪,那么即便你的男友或女友不陪你去,你也很乐意去参加这个节日。但也许你真的厌恶恶劣的天气,若是天气很差,你不可能去参加这个节日。这时候可使用perceptron来对这种决策进行建模。一种方法是为天气选择一个权重w1 = 6,其余条件选择w2 = 2和w3 = 2。 w1的值较大表示天气对你来讲很重要,重要性远远大于你的男友仍是女友是否陪你去,也大因而否有便利的交通工具。最后,假设你为perceptron选择了一个5的阈值。经过这些选择,perceptron实现所需的决策模型,每当天气好的时候输出1,天气很差的时候输出0。不管你的男友仍是女友想去,或者公交是否在附近,输出都没有什么不一样。
经过改变权重和阈值,咱们能够获得不一样的决策模型。例如,假设咱们选择了一个3的门槛,那么perceptron会决定在天气好的时候或交通便利的时候,你的男友或女友愿意陪你的时候去参加这个节日。换句话说,这将是一个不一样的决策模式。下降门槛意味着你更愿意去参加这个节日。
显然,感知器不是一个完整的人类决策模型! 可是,这个例子说明了感知器如何权衡不一样因素以做出决定。 而彷佛合理的是复杂的感知器网络可能会作出至关微妙的决定:
在这个网络中,第一列感知器 :称之为第一层感知器 ,它经过权衡输入的数据,作出三个很是简单的决定。那么第二层感知器呢?这些感知器中的每个都经过权衡第一层决策的结果来作出决定。经过这种方式,第二层中的感知器能够在比第一层中的感知器更复杂和更抽象的层次上作出决定。第三层感知器能够作出更复杂的决定。经过这种方式,感知器的多层网络能够进行复杂的决策。
让咱们简化描述感知器的方式。咱们用w⋅x代替全部w和x的乘积之和,这里的w和x是全部权重和输入的向量。用b代替阀值threshold,使得b=-threshold。因此perceptron公式能够写成:
咱们已经知道,感知器是一种能够衡量输入因素权重并做出决定的方法。如今咱们能够用感知器来表示计算机的基本逻辑函数,例如与非、或、与等函数。下面咱们假设有两个输入,每一个输入的权重都是-2,阀值为3的感知器:
而后咱们看到,输入00时,输出为1。由于-2) 0 +( - 2) 0 + 3 = 3是正数。相似的,输入01或10时,输出1。可是输入11时,输出为0。因此这就实现了与非门NAND的逻辑。
而咱们可使用与非门创建任何的逻辑门阵列。例如,咱们可使用与非门来创建一个电路,它增长了两个比特x1和x2。 这须要计算按位和,x1⊕x2,当x1和x2均为1时进位位被设置为1,即进位位只是乘积x1x2:
咱们将图中carry部分的两个输入变成一个,只须要将权重变为原来的2倍便可:
咱们再将变量也变成一个输入层:
感知器的计算广泛性(就像上面的加法器)同时让人放心有失望。这使人放心的是,感知器网络能够像其余任何计算设备同样强大。但也使人失望,由于它让人以为感知器只是一种新型的NAND门,而不是什么大新闻!
可是,事实证实,咱们能够设计出自动调整网络的权重和误差的学习算法。这种调整是响应外部刺激而发生的,没有程序员的直接干预。这些学习算法使咱们可以以与传统逻辑门彻底不一样的方式使用人造神经元。咱们的神经网络能够简单地学会解决问题,而不是直接设计一个NAND或其余门电路。
学习算法听起来是很是糟糕的。可是咱们要如何为神经网络设计算法呢?假设咱们有一个感知器网络,并想用它来解决一些问题。例如,输入手写数字图片的像素数据,咱们但愿经过神经网络学习调整权重和b的值来正确的识别这些数字。咱们来看一下神经网络是怎么学习的,当咱们调整权重的值时,相应的会改变一些输出的值。因此,目标就变得能够学习了,学习的过程就是不断调整权重和b的值,来改变输出的值,使其输出更加接近真实的值:
例如:当神经网络错误的把9识别成8时,咱们能够经过稍微调整权重和b的值,是其输出结果为9.咱们不断的这么作,直到结果更加好,这就是网络的学习。
可是当权重和b的值有一个小的调整的时候可能会形成感知器的输出彻底的反转,也就是说从0到1.这可能会形成网络的工做变的失控,例如当识别9正确了,可是却形成了别的值识别发生很大的错误。或许咱们会有一些更加聪明的作法来规避这个问题。
咱们可以解决这个问题经过介绍一种新型的人工神经元叫作:sigmoid神经元。它和perceptron 是类似的,可是不一样之处是当权重和b的值作了小的改动时对于输出的结果也只是小小的改变。正是由于这个特性,咱们才选择了它。
OK,让咱们来看一下sigmoid神经元吧。让咱们就像画perceptions时同样来画一下sigmoid神经元:
同perceptron同样,sigmoid神经元有一些输入:x一、x2...可是不一样的是这些输入的值由原来的0或者1替换为0到1之间的值。例如:0.638...等等都是有效的输入值,sigmoid神经元对每个输入值也有权重,w一、w2...,而且也有阀值b。可是输出不是0或1了,而是σ(w⋅x+b),这个σ被叫作sigmoid函数的统称,并被定义为:
把上面的z值用咱们定义的输入、权重和b值替换就获得以下公式:
若是你是第一次看到相似的数学公式,可能会以为这个超难懂,可是实际上,sigmoid神经元和perceptrons有不少的类似处,只是sigmoid神经元能够看到更多的细节。
为了理解sigmoid神经元和perceptrons的类似之处,假设z≡w⋅x+b是一个超大的数,那么e^−z≈0(注意这里的表明幂运算),也就是说σ(z)≈1。换句话说,当z=w⋅x+b这个值很大的时候,输出就是1,相反的当z=w⋅x+b很小的时候,输出就是0,这样的行为是否是和perceptrons的输出很类似呢。那么咱们如何理解σ函数呢?下面是它的形状:
若是σ是一个阶梯函数,那么sigmoid神经元就是perceptron,由于其输出会依赖于w⋅x+b是大仍是小而变成1或者0。可是真实的sigmoid神经元能够看做是一个平滑版的perceptron。这就是说,当试图改变权重Δwj和b的值Δb时,输出值也会有一些小的改变Δoutput。而不会像perceptrons那样发生反转突变。咱们能够将Δoutput的变化理解成下面的公式:
上面的公式表明的是:全部的权重改变量和输出相对于权重偏导数的乘积之和加上输出相对于b的偏导数与 Δb的乘积。若是你对偏导数感受到难以理解也不要慌张,你能够理解成Δoutput相对与Δwj 和 Δb的改变时线性的函数,也就是当稍微改变权重和b的时候,其输出也会跟着有一点小的改变。
咱们应该如何理解sigmoid的输出呢?显然,和感知器不一样的是,sigmoid神经元不只仅输出0和1,它能输出0到1之间的任何实数。这个特性很是有用,例如,咱们想使用输出表明神经网络中像素的强度的时候就能派上用场。但有时候也可能会带来干扰,例如咱们想知道输出是否是9的时候,这时候输出是小数倒不如直接输出0或者1来的直接。但在实践中,咱们能够约定一个值来处理这个问题,例如,决定把输出大于0.5的值表明成9,而小于0.5表明不是9(这里的9只是判断的一个例子而已)。
接下里的一小节我会介绍一个能很好处理识别手写字的神经网络。前期准备,咱们须要理解一下网络各个部分的专业术语。例如咱们有这样一个网络:
最左边一列叫作输入层(input layer),该层的神经元称为输入神经元层。最右边或输出层称为输出神经元(output neurons),例子中只有一个输出神经元。中间这一层叫作隐藏层(hidden layer),例子中只有一个隐藏层,可是不少网络都有多个隐藏层。例以下面图中的4层网络中有2个隐藏层:
因为历史缘由,多层网络也常常被称为多层perceptrons或者MLPs,可是这里咱们只使用单层网络,只是想提醒你一下多层结构的存在。
一般设计网络中的输入和输出层是容易的。例如,判断一个数字是否是9的时候。若是一个image是64*64像素的灰度图,咱们就能够有4,096=64×64个输入神经元,其灰度能够在0和1之间适当调整。输出层会只有一个神经元。其值小于0.5表明图片不是9,大于0.5表明图片是9.
隐藏层的设计就不那么容易了,不可能经过几个简单的经验法则就总结出来隐藏层的设计过程。神经网络的研究人员已经为隐藏层提供了许多设计方案,来帮助咱们从网络中获取咱们想要的行为。例如,能够根据网络学习的时间长短来衡量隐藏层的数量等等。
在神经网络中,若是一层的输出被用做下一层的输入,这种网络叫作前馈神经网络(feedforward neural networks)。意思就是信息老是前馈,没有反馈。可是仍是存在有反馈的人工神经网络模型。这些模型被称为递归神经网络(recurrent neural networks)。在这种模型中,神经元在必定时间内被激活。可是这里咱们将集中精力在前馈神经网络上。
定义了神经网络了,让咱们回到手写字的识别上。咱们把识别手写字分红两个子问题。第一,咱们须要将一系列的数字图片分红一个个的,例如咱们想要将下面的图片:
区分红6部分图片:
第二,当图片被分开之后,程序就须要开始识别每个数字了,例如第一个数字:
咱们会将重点放在解决更难的问题上,就是识别手写数字。咱们将会使用一个3层的神经网络:
上图中输入是784=28×28的图片的像素灰度值,可是图中为了表示方便省略了不少输入神经元。输入中的像素灰度值0表明白色,1.0表明黑色,0和1之间的值表明逐渐变黑的灰色。
第二层是隐藏层。咱们用n表明隐藏层的神经元数量,上图中n=15.
输出层有10个神经元。若是output=1,表明数字是0.
你可能会说表明10个数字为何要用10个输出神经元呢?用4个不就能够表示了么,由于2的4次方是16大于10,足以表示10个数字了。可是实验代表,用10个确实比用4个的学习效果好的多。
让咱们来看一下第一个输出的神经元,这个神经元决定数字是否是0.它经过权衡来自隐藏层的证据来判断这一点,那么隐藏层是怎么作的呢?隐藏层中的第一个神经元检测是否存在以下的图片:
隐藏层经过对目标区域(重叠的区域)进行加权,对其余区域进行轻微加权来实现识别这个图。以这种方式,隐藏层中的第2、第三和第四层来检测下面的图片:
这四部分就是把0分割成的四部分:
若是这个神经网络使用这样的方式来识别数字的,那么咱们来解释一下上面的问题,为何10个输出比4个好。若是有4个输出,那第一次输出的神经元将须要决定图像和哪一个数字的某一个部位更类似,这将会很难处理,由于数字的每一部分组件的形状很难和某个数字密切相关。
如今咱们来设计咱们本身的神经网络,第一件事就是咱们须要收集数据。咱们会使用MNIST data set.关于这个数据集的详解能够去到官网了解。
咱们会使用MINIST中的60000个数据进行训练,称之为训练集。而后用10000个数据进行测试,称之为测试集。
咱们用x表明训练输入,它是28×28=784的多维向量。每个向量表明一张图片的像素灰度值。用 y=y(x)表明输出,是一个10维的向量,例如当输入x=6时,输出y(x)=(0,0,0,0,0,0,1,0,0,0)^T,注意T表明向量的反转(不懂向量相似操做的读者能够先去学习线性代数的基础知识),将横向量转换成列向量。
咱们须要怎么样调整权重和b的值才能使全部的输入x对应的输出都最接近真实的值呢?这里咱们定义损失函数:
式子中w表示权重,b表示阀值,n表示输入个数,a表示x的输入时的输出向量。输出a依赖于w、b和x的值。为了表示简单, ‖v‖表明v向量的长度。咱们把C叫作二次方损失函数;它也叫作均方偏差MSE。C是非负的,若是输出的值a越接近真实值,那么C的值就会越小C(w,b)≈0。因此咱们的目的就是找到一种最好的权重和b值,使得C的值接近0.咱们将使用梯度降低算法来实现这一点。
Okay,咱们用C(v)代替C(w,b),目的是为了表示这多是任何函数。为了最小化C(v),咱们想象一下一个方程只有两个变量,咱们称之为V1和V2:
咱们想要找到C的最小点,这时候咱们可使用微积分来试图寻找这个最小点。咱们可使用导数来寻找C的极值点,对于只有几个变量的函数这样彷佛是行得通的,可是对于大型神经网络的成本函数依赖于数十亿的权重和极其复杂的b值,使用微积分来最小化这个是行不通的,会致使运算量极其庞大。
幸运的是,有一种算法或许可行。假设你在山谷里,想要寻找一条下山最快的路,咱们能够经过计算C的导数来模拟这种清况。为了使问题简单化,咱们来思考一下V1和V2发生一点小变化的时候咱们会在山谷里如何移动?微积分告诉咱们C的变化以下:
咱们的目的就是选择Δv1和Δv2让ΔC最小。咱们把v 的变化定义为向量, Δv≡(Δv1,Δv2)^T,那么C的梯度的偏导数是∇C:
有了这些定义,表达式(7)就能够写成:
这个式子更能表示为何∇C被称为梯度向量:∇C影响着v的改变对C改变的程度。可是不要忘记咱们的目的,是选择Δv使ΔC最小,特别的,假设咱们选择:
其中η是一个小的正参数(称为学习率)。 那么等式(9)ΔC≈-η∇C⋅∇C=-η‖∇C‖2。 由于||C||2≥0,则ΔC≤0,即C老是减少,从不增长。 这正是咱们想要的目的!所以,咱们将采用方程(10)来定义咱们的梯度降低算法中球的“运动定律”。 也就是说,咱们将使用等式(10)来计算Δv的值,而后将球的位置v移动:
只要咱们不断的迭代,就能使C一直减少,直到咱们达到最小点。
为了使梯度降低正确的工做,咱们须要选择学习速率η使得公式(9)足够的小,若是咱们不这么作,可能会形成ΔC>0,这明显是很差的。同时咱们也不能让η过小,那会形成算法执行太慢。
以上解释了当C只有两个变量时的梯度降低,可是实际中C会有不少的变量,假设有m个,v1,…,vm。这时C的变化量ΔC由 Δv=(Δv1,…,Δvm)^T产生:
梯度向量∇C是:
仅仅有两个变量时,咱们能选择:
为了保证公式(12)最小,咱们遵循梯度降低的方法,发现即便是在C有不少变量的时候,也能够经过迭代更新规则达到目的:
你能够将此方法称为梯度降低算法。这种方法给咱们提供了一种经过不断改变v寻找最小C的方法。可是这个方法不是在全部状况都有效的,在后面咱们会提到一些状况。可是在实践中,咱们会发现这是一种使成本函数最小化的有效方式。
那么咱们怎么在神经网络中使用梯度降低呢?在公式(6)中咱们用权重和b来替换v,梯度向量 ∇C有两个组件 ∂C/∂wk 和 ∂C/∂bl,分开写就是:
咱们看一下公式(6),注意一下损失函数的格式:
这是对每个训练例子的平均消耗:
可是当训练数据集过大的时候,计算量也会太大,消耗时间太长。
这时,咱们能够经过随机梯度降低来加速学习,方法是经过随机的从训练数据集中选择小样本计算梯度∇C,经过对这个小样本平均咱们就能够快速获得真实的梯度∇C估计,这有助于加速梯度降低从而学习。
来让随机梯度降低更加的清晰点,随机的从训练集中挑选m个输入X1,X2,…,Xm,咱们但愿选择的m的大小足够可使这些数据的梯度平均值等于全部数据的梯度:
因此:
随机梯度降低中的权重和b的变化:
若是你认真阅读完这篇文章,应该能够从中学习到一些有关机器学习的基础入门概念,那么下一篇文章就让咱们根据这里学到的知识来实现识别手写数字的神经网络吧。
若是个人文章对你有帮助,我建议你能够关注个人文集或者打赏,我建议打赏¥5。固然你也能够随意打赏。
若是有问题,欢迎跟我联系讨论space-x@qq.com.我会尽可能及时回复。