可视化证明:神经网络可以计算任何函数
Tim Chen(motion$) Lv5
  • Original Post

  • 神经网络当中一个最显著的事实是:神经网络能够计算任何的函数。也就是说,假如有人给你一个复杂的,波形弯弯曲曲的函数,$f(x):$

  • 无论是什么的函数,我们都可以保证能找到一个网络,对于所有可能的输入,$x$,$f(x)$的值(或者其他的逼近)就是网络的输出,譬如:

  • 这个网络即使是网络的输入很多的时候也是成立的。$f=f(x_1,…,x_m)$,然后还有很多的输出。譬如,以下就是一个网络,计算的函数,输入$m=3$和输出$n=2$:

  • 以上的网络告诉我们神经网络是有一种泛化性的。无论我们想要计算任何的函数,肯定存在一个网络可以满足我们的需求。

  • 另外,更进一步,即使这个网络限制到只有一层隐含层,这个泛化理论也是成立的。这个网络就是所谓的单层隐含层。所以,即使是很简单的网络也是很厉害的。

  • 搞神经网络的人都应该熟知这个泛化性理论,可是事实上它并没有让很多人能理解。大多数的解释都是偏技术性的。譬如,其中一篇原始的论文利用$Hahn-Banach$理论,$Riesz Representation$理论和一些傅里叶分析来证明这个泛化性理论。如果你不是一个数学家的话,你很难读懂里面的解释。很遗憾,这样很多人就很难懂这个泛化性理论了。但是其实背后的原理是非常简单和美好的。

  • 在本章中,我会给出一个关于泛化性理论的简单的和非常可视化的解释。我们会循序渐进,一步一步来理解这个idea。你将会明白为什么神经网络能够计算任意的函数。你也会理解到这个理论的一些限制的地方。你会理解到这个理论和深度学习之间的关系。

  • 要理解这章的内容,你并不需要读前面的内容。反而这一章是一个结构乐见和完整的文章。我会给你们讲一些神经网络的基本知识,这样你们会更容易看懂解释。我会提供一些临时的链接,以防填补你某一部分知识的缺口。

  • 泛化性理论是计算机科学中一个老生常谈的东西,以至于我们有时候都忘记了它到底有多厉害了。但是我们应该时刻提醒自己:有能力去计算任意的函数真的是一件很厉害的事情。几乎你可以想象得到的任何进程都可以被认为是一个函数的计算。譬如,根据一些短的音乐片段去给一段音乐命名。这也是看作计算一个函数。又或者把中文翻译成英文,又或者给计算机一个mp4视频资料,它会生成一个关于视频的描绘图还有这个视频的拍摄质量。泛化性意味着,原则上,神经网络可以做任何的事情而且更多。

  • 当然,仅仅因为我们知道存在一个网络能够把中文翻译成英文,那不意味着我们就很容易构造甚至识别出这个网络。这样的约束对于模型的传统的泛化性理论,譬如布尔回路,都是适用的。但是,像这本书前面所说的,神经网络对于学习函数有非常强的算法。学习算法和泛化性是一个绝妙的结合。直到现在,这本书还是关注在学习算法。在这一章,我们关注在泛化性理论,和它所代表的意思。

两个说明

  • 在我们解释为什么泛化性理论成立之前,我想要提两个关于“一个神经网络能够计算任何的函数”的说明。

  • 首先,并不是说一个神经网络被用来准确地计算任何的函数。而是,我们能够得到一个关于这个函数的一个很好的逼近。通过增加隐层神经元的个数,我们可以不断改进逼近的程度。譬如,前面我们谈到的神经网络,包含一个隐层。对于很多函数,只有3个隐层神经元的神经网络是一个并不好的逼近。通过增加隐层的神经元(假如,增加到5),我们可以得到更好的逼近:

  • 如果我们继续增加神经元的个数,这个逼近就能做得更好。

  • 更精确的说,假如给定我们一个函数$f(x)$,我们想要计算它的误差$\epsilon > 0$。只要我们增加足够的隐层神经元,我们就能找到一个神经网络,它的输出$g(x)$满足$g(x)-f(x) < \epsilon$,对于所有的输入$x$。换句话说,这个逼近函数$g(x)$对于所有可能的输入都在可预计的准确度范围之内。

  • 第二个说明是能够用逼近的方式的函数类型是连续函数。如果一个函数是不连续的,譬如,突然断开的,或者跳动的函数,然后是没法用神经网络来进行逼近的。这并没有什么奇怪的,因为我们的网络计算输入的连续函数。然而,即使我们想要计算不连续的函数,但是利用连续的逼近来的效果更好。既然这样,那么我们就可以用神经网络。实际上,这并不是一个很重要的限制。

  • 总结一下,关于泛化性理论的一个精确的说法是一个单隐层的神经网络能够用来逼近任何的连续函数到任何想要的精度。在本章中,我们实际上证明了一个微弱版本的理论,用两个隐层的神经网络代替单隐层的神经网络。在以下的我们将要解释的问题中,利用一些小技巧,适合的给出了单隐层的神经网络的证明。

一个输入和一个输出的泛化理论

  • 要理解为什么泛化性理论是可行的,让我们从理解如何构造一个能够逼近函数的只包含一个输入和一个输出的神经网络说起:

  • 其实最简单的神经网络(包含一个输入和一个输出)就是泛化性理论的核心。一旦我们能够理解这个简单的网络,那么我们也很容易扩展到其他的(包含多个输入和输出)复杂网络了。

  • 想要深入理解如果构造能够计算函数$f$的网络,我们先来构造一个简单的神经网络,包含单个输入,一个包含2个神经元的隐层,单个输出的神经网络:

  • 为了感受一下神经网络中的组件是如何工作的,让我们先看上面的隐层神经元。在下面的图中,用鼠标点击然后拖动来改变权重$w$的值。你就可以立刻看到右边的函数图是如何变化的(原网页才能操作):
  • 本书的前面讲过,$\sigma(wx+b)$是怎么计算的,其中$\sigma(z)=1/(1+e^{-z})$就是sigmoid函数。到现在,我们一直频繁的使用这种代数形式进行计算。但是要证明泛化性理论,我们应该忽视这种数学形式,然后通过通过操作和观察以上的图来获得更深的理解。
  • 要开始证明这个理论,请试着用鼠标点击偏置$b$,然后往右拉来增加它的数值。你会看到增加偏置$b$只会把图像往左移动,而不会改变图像的形状。
  • 接下来,你试着鼠标往左拉,偏置$b$的数值减小,你会看到图像是往右边移动的,同样的,图像的形状并没有改变。
  • 然后,我们来改变权重$w$的数值,把它的值改变到2或者3。你会看到减小权重$w$,曲线变得更宽了。你可能需要同时改变一下偏置$b$,以免图像跑出了框内。
  • 最后,把权重$w$的数值增加到100。你会发现,曲线变得更陡峭了,直到它看起来像一个step函数。可以观察一下下面的小视频:
  • 我们可以通过增加权重$w$直到它变成了一个step函数(逼近的精度越来越高)来简化我们的分析。下面右边的图像是当$w=999$时的函数图。
  • 其实step函数比一般的sigmoid函数表现更好。原因是输出层是前面所有的隐层的神经元计算来决定的。去分析一堆step函数的总和是件更容易的事,但是去分析一堆sigmoid函数的曲线计算后的结果就不是一件易事了。而且,把隐层的神经元输出step函数是一件更容易的事情。更确切的说,我们把权重$w$的值调得非常大,这样就可以得到了step函数了。然后通过调整偏置$b$来改变step(跃阶)的位置。当然,把输出当成一个step函数也是一种逼近,而且是一个很好的逼近,而现在我们正是这样做的。我稍后会再讨论这种逼近的求导的影响。

  • 当$x$的数值是多少时达到跃阶(step)呢?换一种说法,step的位置是如何由权重$w$和偏置$b$来决定的?

  • 要回答这个问题,我们再来试一下改变权重$w$和偏置$b$的数值。你可以弄清楚跃阶(step)和权重$w$与偏置$b$的关系吗?通过不断的观察图像的变化,你可能就会发现,跃阶(step)的位置是和偏置$b$成正比的,和权重$w$成反比的。

  • 事实上,跃阶(step)的位置$s$满足$s=-b/w$.

  • 这会大大简化了我们的生活,如果我们只是单单利用一个参数$s$来描述隐层的神经元的话。$s$就是跃阶(step)的位置,$s=-b/w$。

  • 上面有提到,我们可以偷偷地把输入的权重$w$调到非常大,大到出来的step函数是一个很好的逼近。我们就可以很容易的在传统的模型当中把神经元参数按这样子来调整,偏置$b=-ws$.

  • 以上我们都是讨论上层神经元。现在我们来讨论一下整个网络。我们假设上层神经元通过step函数参数化跃阶(step)为$s_1$,下层神经元通过step函数参数化跃阶(step)为$s_2$.他们分别有输出权重$w_1$和$w_2$。以下就是网络:

  • 右上方的图像是输出权重$(w_1a_1+w_2a_2)$的结果。其中$a_1$和$a_2$分别是上层神经元和下层神经元的输出。输出用$a$来表示是因为神经元通常包含一个激活函数(activation)。

  • 让我们来看一下$s_1$和$s_2$相遇时会发生什么情况呢?看图:

  • 可以看到,当我们操作$s_1$时,$S_1$和$s_2$相遇时,$S_1$就会带动$s_2$走。所以,图像的变动,我们也要分是$s_1$先动还是$s_2$先动。

  • $h_t$

 评论