使用神经单元去识别手写数字
人类视觉系统是世界奇观之一。请考虑以下手写数字的顺序:
大多数人毫不费力地认出这些数字是504192。这种简单是具有欺骗性的。在我们大脑的每一个半球,人类有一个主要的视觉皮层,也叫V1,包含1.4亿个神经元,它们之间有数百亿的连接。然而,人类的视觉不仅包括V1,还包括一系列的视觉皮质——V2、V3、V4和V5——逐步进行更复杂的图像处理。我们的脑袋是一台超级计算机,经过几亿年的进化,已经能够很好地适应这个视觉世界。识别手写数字并不容易。相反,我们人类是惊人的,惊人地善于理解我们的眼睛向我们展示的东西。但几乎所有的工作都是在无意识中完成的。因此,我们通常不会意识到我们的视觉系统解决了多么困难的问题!
如果你试图编写一个计算机程序来识别上面的数字,那么视觉模式识别的难度就变得明显了。当我们自己突然变得非常困难时,似乎很容易。关于我们如何识别形状的简单直觉——“一个9在顶部有一个循环,右下方有一个垂直的冲程”——结果不太简单,可以用算法来表达。当你试图精确地制定这些规则时,你很快就会迷失在一些例外和警告和特殊情况下。看来无望。
神经网络以不同的方式处理这个问题。这个想法是用大量的手写数字,被称为训练实例:
然后开发一个可以从这些训练实例中学习的系统。换句话说,神经网络使用这些例子来自动推断识别手写数字的规则。此外,通过增加训练样本的数量,网络可以学习更多关于书法的知识,从而提高其准确性。因此,虽然我只展示了上面的100个训练数字,但也许我们可以通过使用数千甚至数百万或数十亿的训练示例来构建一个更好的手写识别器。
在本章中,我们将编写一个计算机程序,实现一个学习识别手写数字的神经网络。这个程序只有74行,没有特殊的神经网络库。但这个简短的程序可以识别数字,准确率超过96%,没有人为干预。此外,在后面的章节中,我们将会开发出能提高准确度超过99%的想法。事实上,最好的商业神经网络现在已经很好了,银行可以用它们来处理支票,并通过邮局来识别地址。
我们关注的是手写识别,因为它是一个很好的原型问题,用来学习一般的神经网络。作为一个原型,它达到了一个最佳的位置:它具有挑战性——识别手写数字并不是一个小的壮举——但它并不像需要一个极其复杂的解决方案,或者是巨大的计算能力那么困难。此外,这是一个开发更高级技术的好方法,比如深度学习。所以在整本书中,我们会反复回到手写识别的问题。在后面的书中,我们将讨论这些思想如何应用到计算机视觉的其他问题,以及在语言、自然语言处理和其他领域。
当然,如果这一章的重点仅仅是写一个计算机程序来识别手写的数字,那么这个章节就会短得多!但在此过程中,我们将发展许多关于神经网络的关键思想,包括两个重要类型的人工神经元(感知机和sigmoid神经元),以及神经网络的标准学习算法,即随机梯度下降法。在整个过程中,我把重点放在解释为什么事情是这样做的,以及建立你的神经网络直觉。这需要一个更长的讨论,而不是我刚刚介绍了正在发生的事情的基本机制,但这是值得的,因为你会获得更深的理解。在这一章的结尾,我们将会了解深度学习是什么,以及为什么它很重要。
感知机:
什么是神经网络?为了开始,我将解释一种叫做感知机的人造神经元。感知机是由科学家Frank Rosenblatt在上世纪50年代和60年代开发出来的,灵感来自于Warren McCulloch和Walter Pitts的早期作品。今天,在这本书中,使用其他的人工神经元模型是比较常见的,在神经网络的现代工作中,主要的神经元模型是一个叫做sigmoid神经元的模型。我们很快就会讲到sigmoid神经元。但要理解为什么sigmoid神经元被定义为它们的方式,就值得花时间去了解感知机。
那么感知机是如何工作的呢?感知机需要几个二进制输入,x1,x2,…,并产生一个二进制输出:
在这个例子中,感知机有三个输入,x1,x2,x3。一般来说,它可以有更多或更少的输入。Rosenblatt提出了一个计算输出的简单规则。他介绍了权重,w1 w2,…,实数表达各自的输入输出的重要性。0或1,神经元的输出是由加权和是否∑jwjxj小于或大于某个阈值。就像权重一样,阈值是一个实数,它是神经元的一个参数。用更精确的代数术语来说:
这就是感知机的工作原理!
这是基本的数学模型。你能想到感知机的一种方法是它是一种通过权衡证据做出决定的设备。让我举个例子。这不是一个很现实的例子,但很容易理解,我们很快就会看到更现实的例子。假设周末即将到来,你听说在你的城市将会有一个奶酪节。你喜欢奶酪,并且正在决定是否去参加这个节日。你可以通过权衡三个因素来做出决定:
1、天气好吗?
2、你的男朋友或女朋友想陪你吗?
3、这个节日临近公共交通吗?(你没有车)。
我们可以用相应的二元变量x1,x2,x3来表示这三个因子。例如,如果天气好,我们就有x1 =1,如果天气不好,x1 =0。同样的,如果你的男朋友或女朋友想去,则x2 =1,如果没有,x2 =0。类似的x3即表示附近有没有公共交通。
现在,假设你非常喜欢奶酪,所以即使你的男朋友或女朋友不感兴趣,而且这个节日很难去,你也很乐意去参加这个节日。但也许你真的讨厌坏天气,如果天气不好,你就不可能去参加这个节日。你可以用感知机来模拟这种决策。这样做的一种方法是选择一个权重w1 =6来表示天气的重要性,用w2 =2和w3 =2来表示其他条件。w1的更大的权重表明,天气对你来说很重要,比你的男朋友或女朋友加入你,或者公共交通的接近程度更重要。最后,假设你为感知机选择了5的阈值。有了这些选择,感知机实现了所需的决策模型,在天气好的时候输出1,而在天气不好的时候则输出0。不管你的男朋友或女朋友是否想去,还是附近是否由公共交通,这对你的决策没有影响。
通过改变权重和阈值,我们可以得到不同的决策模型。例如,假设我们选择的阈值为3。这个节日party附近公共交通,并且你的男朋友或女朋友也愿意加入你的行列感知机就会决策,无论天气好坏,你都应该去参加这个节日。换句话说,这就成了一个不同的决策模式。而降低这个门槛也意味着你更愿意去参加这个节日。
显然,感知机并不是人类决策的完整模型!但这个例子说明了一个感知机如何权衡不同的证据来做出决定。一个复杂的感知机网络可以做出非常微妙的决定,这似乎是合理的:
在这个网络中,感知机的第一列——我们称之为第一层感知机——通过权衡输入的证据,做出三个非常简单的决定。第二层的感知机呢?每一个感知机都通过权衡第一层决策的结果来做出决定。这样一来,第二层的感知机就能比第一层的感知机做出更复杂、更抽象的决策。更复杂的决策可以由第三层的感知机做出。这样,一个多层感知机网络就可以进行复杂的决策。
顺便说一下,当我定义感知机时,我说感知机只有一个输出。在上面的网络中,感知机看起来像是有多个输出。事实上,它们仍然是单一输出。多个输出箭头仅仅是一种有用的方法,表示感知机的输出被用作其他几个感知机的输入。它不像绘制一条输出线那样笨拙,然后分割。
让我们简化描述感知机的方式。阈值条件∑jwjxj >阈值很麻烦,我们可以做两个符号改变来简化它。第一个变化是编写∑jwjxj点积,w⋅x≡∑jwjxj。w,x分别是权重向量的分量和输入。第二个变化是把阈值移到不等式的另一边,所谓的感知机的偏差,b来替代它,b≡−threshold也就是b≡−阈值。使用偏差而不是阈值,感知机规则可以重写:
你可以把偏差看作是测量感知机输出1的容易程度。或者用更生物学的术语来说,偏差是测量感知机**的容易程度。对于一个有很大偏差的感知机,感知机输出1是非常容易的。但是如果偏差是非常消极的,那么感知机就很难输出1。很明显,引入偏差只是我们描述感知机的一个很小的改变,但是稍后我们会看到它导致进一步的符号简化。正因为如此,在剩下的书中我们不使用阈值,我们总是使用偏表示。
我把感知机描述为衡量证据做出决策的方法。感知机的另一种方法是计算我们通常认为的基础计算的基本逻辑函数,比如和,或者,和与非。例如,假设我们有一个感知机有两个输入,每个2权重为−2,整体偏差3。这是我们的感知机:
很明显,当我们输入 0 0,我们会得到 0*(-2) + 0*(-2) +3 =3 为正的。即输入0 0,输出为1,当输入1 0 或是 0 1时,同样可以得到1,但是我们输入1 1时,则输出为-1,我们就实现了与非门的功能。
与非门示例表明,我们可以使用感知机来计算简单的逻辑函数。事实上,我们可以使用感知机网络来计算任何逻辑函数。原因是与非门是通用的计算,也就是说,我们可以在与非门中建立任何计算。例如,我们可以使用与非门来构建一个添加两个比特,x1和x2的电路。这需要计算位和,x1⊕x2以及一个进位设置为1当x1和x2都为 1时,携带位只是位乘x1x2:(举例,用与非门实现加法运算)
为了得到一个等价的感知机网络,我们替换所有的与非门感知机,有两个输入,每个权重都是−2,总体偏差为3。这是最终的网络。注意,我移动了感知机,它对应于右下角的与非门,只是为了更容易画出图上的箭头:
这个感知器网络的一个值得注意的方面是,最左侧感知器的输出被用作输入到最底部的感知器的两倍。当我定义感知器模型时,我并没有说是否允许这种双重输出。实际上,这没什么大不了的。如果我们不想让这种事情发生,那么就可以简单地将这两条线合并成一个单独的连接,它的权重为- 4,而不是两个- 2个权重的连接。(如果你没有发现这一点,你应该停下来向自己证明这是等价的。)有了这个变化,网络看起来如下,所有未标记的权重等于- 2,所有偏差等于3,并且单个权重为- 4,标记为:
到目前为止,我一直在绘制x1和x2这样的输入,因为变量在感知机网络的左侧浮动。事实上,传统的方法是多画一层感知机——输入层——来编码输入:
输入感知机的符号,我们有输出,但没有输入:
(如何理解输入层)这是一种速记。它实际上并不意味着一个没有输入的感知机。为了看到这个,假设我们有一个没有输入的感知机。然后加权和∑jwjxj总是为零,所以感知机将输出1如果b > 0 ,如果b≤0 则会输出0。也就是说,感知机只输出一个固定值,而不是期望的值(如上面例子中的x1)。最好认为输入感知机不被感知机,而是特殊单位,只是定义为输出所需的值,x1,x2, ,…。
增加的这个例子演示了一个感知机网络如何被用来模拟一个包含许多与非门的电路。由于与非门是通用的计算方法,因此,感知机也是通用的计算方法。
感知机的计算通用性既让人安心又令人失望。这让人安心,因为它告诉我们,感知机的网络可以和任何其他计算设备一样强大。但它也令人失望,因为它使感知机似乎只是一种新型的与非。但这肯定不是大新闻!
然而,情况比这一观点显示的要好。事实证明,我们可以设计出一种学习算法,它可以自动调整人工神经元网络的权重和偏差。这种调优是在外部刺激的情况下发生的,而不需要程序员的直接干预。这些学习算法使我们能够以一种与传统的逻辑门截然不同的方式使用人工神经元。我们的神经网络可以简单地学习解决问题,而不是显式地设置与非门和其他的电路,有时会很难直接设计一个传统的电路。(传统的也是这样一个个与非逻辑门来形成强大的计算能力的)
神经元:
这是听起来很棒的学习算法。但是我们怎样才能为神经网络设计出这样的算法呢?假设我们有一个感知机网络,我们想用它来学习解决一些问题。例如,对网络的输入可能是扫描的原始像素数据,手写的数字图像。我们希望网络能学习权重和偏差,这样网络的输出就能正确地分类数字。为了了解学习如何工作,假设我们在网络中做了一个小的改变(或偏差)。我们想要的是,这个小的变化,只会引起网络输出的一个很小的相应变化。稍后我们将看到,这个属性将使学习成为可能。在图式上,这是我们想要的(显然这个网络太简单了,不能用来做手写识别!)
如果重量的微小变化(或偏差)只导致输出的微小变化,那么我们就可以利用这个事实来修改权重和偏差,以使我们的网络以我们想要的方式表现得更多。例如,假设网络在应该是“9”的时候错误地将图像分类为“8”。我们可以弄清楚如何在权重和偏差上做一个小的改变,这样网络就更接近于将图像分类为“9”。然后我们重复这个过程,通过改变权重和偏差来产生更好的输出,而这个优化过程就是网络在就是在不断学习。
(解释了为什么需要引入**函数)问题是,当我们的网络中包含感知机时,就不会发生这种情况。事实上,网络中任何一个感知机的权重或偏差的微小变化,有时会导致感知机的输出完全翻转,从0直接反转到1。而这种翻转可能会导致网络其他部分的行为以某种非常复杂的方式完全改变。因此,当你的“9”可能被正确分类时,网络在所有其他图像上的行为很可能会以某种难以控制的方式完全改变。这使得我们很难看到如何逐步修改权重和偏差,从而使网络更接近期望的行为。也许有一些聪明的方法来解决这个问题。但我们如何才能得到一个感知机的网络,这并不是显而易见的。(Perhaps there’s some clever way of getting around this problem. But it’s not immediately obvious how we can get a network of perceptrons to learn.)
我们可以通过引入一种叫做sigmoid神经元的新型人工神经元来克服这个问题。Sigmoid神经元与感知机相似,但经过修改后,其权重和偏差的微小变化只会导致其输出的微小变化。这是一个非常关键的点,即能允许一个s形神经元网络去实现学习。(**函数)
让我来描述一下s形神经元。我们将以同样的方式描绘sigmoid神经元我们描绘了感知机:
就像一个感知机,神经元输入,x1,x2,……。但是,这些输入不仅可以是0或1,也可以在0到1之间取值。例如,0.638…是一个有效的输入神经元S型。也就像一个感知机,神经元权值为每个输入,w1,w2,…,和一个总体偏差,b。但是输出不是0或1。相反,它是σ(w⋅x + b),σ叫做
Lohistic function逻辑函数或者逻辑神经元:
更详细的带入上述公式,我们就可以得到如下公式:
乍一看,sigmoid神经元与感知机的表现非常不同。如果你还不熟悉sigmoid函数的代数形式,那么它就显得不透明和令人生畏。事实上,感知机和sigmoid神经元之间有许多相似之处,而sigmoid函数的代数形式更多的是一个技术细节,而不是真正的理解障碍。
理解感知机模型的相似性,我们假设z≡w⋅x + b是一个很大的正数。然后e−z≈0则 e-z≈0所以σ(z)≈1。换句话说,当z = w⋅x + b很大且为正,则神经元的输出大约是1,这就和之前的感知机是一样的了。另一方面假设z = w⋅x + b是非常负数。然后e−z→∞,则我们有σ(z)≈0。所以当z = w⋅x + b是一个很大的负数,神经元的行为也密切接近一个感知机。只有当w⋅x + b是中等大小,从感知机模型有很多偏差。
那么σ的代数形式呢?我们怎么去理解呢?事实上,σ的确切形式不重要,真正重要的是绘制时它的函数形状下图是它的形状:
这个形状其实就是阶跃函数的平滑版本:
如果σ实际上是一个阶跃函数,那么**神经元就是一个感知机,因为输出1或0完全取决于w⋅x + b实际上是积极的还是消极的。(当w⋅x + b = 0时感知机输出0,而阶跃函数输出1。严格地说,我们需要在这一点上修改阶跃函数)通过使用实际σ函数得到,正如上面已经暗示的,感知机的平滑过程。事实上,它的平滑σ功能是至关重要的,而不是它的具体形式。Σ函数的平滑变化意味着很小的权重Δwj和Δb偏差变化只会产生Δoutput神经元的一个很小的输出。事实上,微积分告诉我们Δoutput很近似于:
上式子和是输出对于权重wj和偏差b的偏微分,如果你对偏导数不熟悉,也不要惊慌!虽然上面关于偏导数的表达式看起来很复杂,但它实际上是在说一些很简单的事情。一个核心的好消息是Δoutput是一个随权重变化Δwj和偏差变化Δb线性变化的函数。这种线性使得我们能以微小的权重和偏差变化来实现任何期望的输出中的微小变化。因此,虽然sigmoid神经元与感知机有很多相同的定性行为,但它们使得我们更容易理解计算权重和偏差的变化会如何改变输出。
如果我们的σ函数是形状重于形式,那么为什么使用类似于方程(3) σ的特殊形式?事实上,后来在书中我们偶尔会考虑神经元的输出为f(w⋅x + b),即他的**函数为f(⋅)。当我们使用不同的**函数时,最主要的变化是方程(5)中偏导数的特殊值。事实证明,当我们计算这些偏导数后,我们发现使用σ函数将简化代数计算,因为当指数函数在求导的时候有令人欣喜的特性。在任何情况下,σ都是常用的神经网络的**函数,我们这本书也将经常使用这个函数。
我们应该如何解释sigmoid神经元的输出呢?显然,感知机和sigmoid神经元之间的一个很大的区别是sigmoid神经元不只是输出0或1。他们可以作为输出任意实数0至1,所以例如一般值为 0.173和0.698等等…是合法的输出。这可能是有用的,例如,如果我们想使用输出值来表示图像输入到神经网络中像素的平均强度。但有时也会令人讨厌。假设我们希望网络的输出显示“输入图像是9”或“输入图像不是9”。显然,如果输出是0或1,就像在感知机中那样做是最容易的。但是在实践中,我们可以设置一个约定来处理这个问题,例如,通过决定大于0.5的任何输出解释为“9”,并且任何输出小于0.5,则表示“not a 9”。当我们使用这样的约定时,我总是明确地声明,所以它不应该引起任何混乱。
练习:
模拟感知机的Sigmoid神经元
一、 假设我们在一个感知机的网络中取所有的权值和偏差,然后乘以一个正的常数c> 0。显示网络的行为不会改变。
二、 假设我们有和最后一个问题相同的设置——一个感知机网络。假设还选择了感知机网络的整体输入。我们不需要实际的输入值,我们只需要输入能被修复就可以。假设权重和偏见,w⋅x + b≠0输入x的任何特定的感知机网络。现在用sigmoid神经元替换网络中的所有感知机,并将权重和偏差乘以一个正的常数c> 0。表明,当c→∞**神经元网络的行为感知机网络是完全一样的。当w⋅x + b = 0时,这种神经元怎么才会失败呢?
(翻译能力有限,可以对照英文一起看)