
1.2 神经网络的简单介绍
神经网络是一个函数(用f表示),它试图近似另一个目标函数g,可以用以下公式来描述这种关系:
g(x)≈fθ(x)
在此处,x为输入数据,而θ是神经网络的参数(权值)。目标是找到这样的最佳近似函数g的超完备参数θ。这个通用的定义适用于两者:回归(近似g的精确值)和分类(将输入分配到多个可能的类中的一个类)任务。神经网络函数也可以表示为f(x;θ)。
我们将从神经网络的最小组成部分——神经元开始讨论。
1.2.1 神经元
前面的定义是神经网络的鸟瞰图。现在讨论神经网络的基本构件,即神经元(或单元)。单元是数学函数,其定义如下:

公式解释如下:
- y是输出单元(单值)。
- f是非线性可微激活函数。在神经网络中,激活函数是神经网络中非线性的来源——如果神经网络是完全线性的,它只能近似其他线性函数。
- 激活函数的参数是所有输入单元xi(n为总输入)和偏置权重b的加权和(权重wi)。输入xi可以是数据输入值,也可以是其他单元的输出。
另外,可以用其向量表示替换xi和wi,其中x=(x1,x2,…,xn),w=(w1,w2,…,wn)。此处,公式将使用两个向量的点积:
y=f(x·w+b)
下图(左)显示了一个神经元。

左:一个单元及其等价公式;右:感知器的几何表示
如果x·w=0,输入向量x将垂直于权重向量w。因此,所有在x·w=0处的x定义了一个向量空间ℝn中的超平面,其中n是x的维数。在二维输入(x1,x2)的情况下,可以将超平面表示为一条直线。这可以用感知器(或二元分类器)来说明,感知器是一个有阈值激活函数的神经元,可以将输入分为两类中的一个。有两个输入(x1,x2)的感知器的几何表示是分隔这两个类的一条线(或判定边界)(上述图的右图)。这给神经元带来了严重的限制,因为它不能对线性不可分问题进行分类,即使是像XOR这样简单的问题。
具有恒等激活函数(f(x)=x)的单元等价于多元线性回归,具有sigmoid激活函数的单元等价于逻辑回归。
接下来,学习如何分层组织神经元。
1.2.2 层的运算
神经网络组织结构的下一层是单元层,其中将多个单元的标量输出组合在一个输出向量中。层中的单元没有互相连接。这种组织结构有其合理性,原因如下:
- 可以将多元回归推广到一个层,而不是单一单元的线性回归或逻辑回归。换句话说,可以用一个层来近似多个值,而不是用一个单元来近似单个值。这种情况发生在分类输出的情况下,其中每个输出单元表示输入属于某个类的概率。
- 一个单元可以传递有限的信息,因为它的输出是标量。通过组合单元输出,而不是单个激活,可以考虑整个向量。这样,就可以传递更多的信息,不仅因为向量有多个值,而且因为它们之间的相对比率具有额外的含义。
- 因为层中的单元彼此之间没有连接,所以可以将它们的输出计算并行化(从而提高计算速度)。这种能力是近年来DL成功的主要原因之一。
在经典的神经网络(即DL之前的神经网络,当时它们只是许多ML算法中的一种)中,层的主要类型是全连接(FC)层。在这一层中,每个单元从输入向量x的所有分量接收加权输入。假设输入向量的大小为m,FC层有n个单元和一个激活函数f,这对于所有的单元都是一样的。n个单元中的每一个都有m个权重,一个权重对应m个输入中的一个。下面是FC层单个单元j的输出公式。其与1.2.1节中定义的公式相同,但此处将包含单元索引:

此处,wij为第j层单元与第i个输入分量之间的权重。可以将连接输入向量和单元的权重表示为一个m×n的矩阵W。每个矩阵列表示一个层单元的所有输入的权重向量。在本例中,该层的输出向量是矩阵-向量乘法的结果。但是,也可以将多个输入样本xi组合成一个输入矩阵(或批量)X,它将同时通过该层。这种情况下,使用矩阵-矩阵乘法,其层输出是一个矩阵。下图是一个FC层的示例,以及批量和单例场景中的等效公式:

具有向量/矩阵输入和输出及其等价公式的FC层
我们明确地分离了偏差矩阵和输入权重矩阵,但在实践中,底层实现可能使用共享的权重矩阵,并在输入数据中附加一行1。

一个具有输入张量和输出张量的函数
DL不限于FC层,还有许多其他类型,比如卷积层、池化层等。有些层具有可训练的权重(FC层、卷积层),而其他层没有(池化层)。还可以将术语函数或运算与层互换使用。例如,在TensorFlow和PyTorch中,刚才描述的FC层是两个顺序运算的组合。首先,执行权重和输入的加权和,然后将结果作为输入提供给激活函数运算。实践中(使用DL库的时候),神经网络的基本构造块不是单元,而是以一个或多个张量为输入并输出一个或多个张量的运算。
接下来,讨论如何在一个神经网络中组合层运算。
1.2.3 神经网络
在1.2.1节,我们证明了一个神经元(对层也有效)只能分类线性可分的类。为了克服这一限制,必须在一个神经网络中组合多个层。把神经网络定义为运算的有向图(或层)。图节点是运算,它们之间的边决定了数据流。如果两个运算是相连的,那么第一个运算的输出张量将作为第二个运算的输入,这个输入由边的方向决定。一个神经网络可以有多个输入和输出——输入节点只有传出边,而输出节点只有传入边。
根据这一定义,可以确定两种主要类型的神经网络:
- 前馈神经网络,用无环图表示。
- 循环神经网络(RNN),用循环图表示。循环是暂时性的;图中的回路连接传播t-1时刻某个运算的输出,并将其反馈给下一个时刻t的网络。RNN保持一种内部状态,它代表了之前所有网络输入的一种总结。这个总结以及最新的输入被提供给RNN。网络产生一些输出,但也更新它的内部状态,并等待下一个输入值。这样,RNN就可以接受长度可变的输入,比如文本序列或时间序列。
下图是这两种网络的一个例子。

左:前馈网络;右:循环网络
假设,当一个运算接收到来自多个运算的输入时,使用元素依次求和来组合多个输入张量。然后,可以把神经网络表示为一系列嵌套的函数或运算。用f(i)(x)表示神经网络,其中i是帮助我们区分多种运算的一些索引值。例如,上图中左边的前馈网络的等效公式如下:

在图右侧的RNN公式为:

用与运算本身相同的索引表示运算的参数(权重)。取一个索引为l的FC网络层,它从索引为l-1的前一层获取输入。以下是带有层索引的单个单元和向量/矩阵层表示的层公式:

我们已经熟悉了完整的神经网络架构,现在讨论不同类型的激活函数。
1.2.4 激活函数
让我们讨论不同类型的激活函数,从经典的开始:
- sigmoid:它的输出边界在0和1之间,可以解释为神经元激活的概率。由于这些性质,长期以来,sigmoid是最常用的激活函数。然而,它也有一些不太受欢迎的特性(稍后会详细介绍),这导致了它的受欢迎程度下降。下图展示了sigmoid公式、它的导数以及其图像(在我们讨论反向传播时导数很有用)。

sigmoid激活函数
- 双曲正切(tanh):这个名字说明了一切。与sigmoid的原则性区别是tanh在(-1,1)内。下图展示了tanh公式及其导数。

双曲正切激活函数
接下来,关注这个模块的“新人”——函数家族的*LU(LU代表线性单元)。从线性整流函数(ReLU)开始,它在2011年首次成功使用(“Deep Sparse Rectifier Neural Networks”,http://proceedings.mlr.press/v15/glorot11a/glorot11a.pdf)。下页图给出ReLU公式及其导数。
正如我们所看到的,当x>0时,ReLU重复它的输入,反之则保持为0。与sigmoid和tanh相比,这种激活函数有几个重要的优势:
- 它的导数有助于防止梯度消失(在1.3.4节有更多介绍)。严格地说,ReLU在值为0处的导数是未定义的,这使得ReLU只能是半可微的(更多信息可以在https://en.wikipedia.org/wiki/Semidifferentiability上找到)。但在实践中,它运行得很好。

ReLU激活函数
- 它是幂等的——如果传递一个值给任意数量的激活函数,它不会改变。例如ReLU(2)=2,ReLU(ReLU(2))=2,依此类推。对于sigmoid,情况不是这样的,它的值在每次传递时都被压缩:σ(σ(2))=0.707。下图是一个sigmoid激活函数连续三次激活的例子。
-
连续激活sigmoid函数“压缩”数据
ReLU的幂等性使其在理论上可以创建比sigmoid层更多的网络。
- 它创建了稀疏激活——让我们假设网络的权值是通过正态分布随机初始化的。此处,每个ReLU单元的输入都有0.5的概率小于0。因此,大约一半的激活函数的输出也是0。稀疏激活有许多优点,可以将其粗略地概括为在神经网络环境中的奥卡姆剃刀——使用更简单的数据表示比使用复杂的数据表示能更好地得到相同的结果。
- 前向和反向传递的计算速度都比sigmoid的计算速度更快。
然而,在训练时,网络权值可以更新为这样一种方式,即某一层中的ReLU单元总是接收到小于0的输入,从而使它们也永久地输出为0。这种现象被称为“dying ReLU”。为了解决这个问题,对ReLU进行一些修改。以下是一份不太详尽的列表:
- Leaky(泄漏)ReLU:当输入大于0时,Leaky ReLU会像常规ReLU一样重复输入。但是,当x<0时,Leaky ReLU输出的是x乘以某个常数α(0<α<1),而不是0。下面的图给出了Leaky ReLU公式、它的导数,以及其对应的图。
-
Leaky ReLU激活函数
- 参数化ReLU(PReLU,“Delving Deep into Rectifiers:Surpassing Human-Level Performance on ImageNet Classification”,https://arxiv.org/abs/1502.01852):该激活与Leaky ReLU相同,但参数α是可调的,并在训练期间进行调整。
- 指数线性单元(ELU,“Fast and Accurate Deep Network Learning by Exponential Linear Units(ELU)”,https://arxiv.org/abs/1511.07289):当输入大于0时,ELU和ReLU一样重复输入。但是,当x<0时,ELU输出变为f(x)=α(ex-1),其中α是可调参数。下图为α=0.2时的ELU公式、它的导数及其对应的图。
-
ELU激活函数
- 缩放指数线性单元(SELU,“Self-Normalizing Neural Networks”,https://arxiv.org/abs/1706.02515):这个激活类似于ELU,区别为输出(都小于或大于0)是根据额外的训练参数λ来缩放。SELU是一个更大的概念——自归一化神经网络(SNN)的一部分,它在上述论文中有描述。SELU公式如下:

最后,我们将提到softmax,它是分类问题中输出层的激活函数。假设最终网络层的输出是一个向量z=(z1,z2,…,zn),其中n个分量代表输入数据属于n个可能的类中的一个的概率。此处,每个向量分量的softmax输出如下:

这个公式中的分母可以作为一个归一化器。softmax输出有一些重要的属性:
- 每个f(z)的值都在[0,1]范围内。
- z的值的总和等于1:∑jf(zj)=1。
- 一个额外的好处(实际上是必需的)是这个函数是可微的。
换句话说,可以将softmax输出解释为一个离散随机变量的概率分布。然而,它还有一个特性。在归一化数据之前,用指数ezi变换每个向量分量。假设两个向量分量是z1=1和z2=2。此处exp(1)=2.7,exp(2)=7.39。正如所看到的,变换前后各分量的比率差别很大——0.5和0.36。实际上,与较低的分数相比,softmax提高了获得较高分数的可能性。
下一节将把注意力从神经网络的构建模块转移到它的整体上。更具体地说,我们将演示神经网络如何近似任意函数。
1.2.5 通用逼近定理
通用逼近定理在1989年被首次证明,通过具有sigmoid激活函数的神经网络,然后在1991年,通过具有任意非线性激活函数的神经网络被再次证明。它指出,在ℝn的紧致子集上的任意连续函数可以由具有至少一个隐藏层、有限单元数和非线性激活的前馈神经网络逼近到任意准确率。虽然具有单一隐藏层的神经网络在很多任务中表现不佳,但该定理仍然告诉我们,在神经网络中没有理论上不可逾越的限制。这个定理的正式证明太复杂了,此处无法解释,但我们将尝试用一些基础数学来提供一个直观的解释。
下面这个例子的灵感来自Michael A.Nielsen的书Neural Networks and Deep Learning(http://neuralnetworksanddeeplearning.com/)。
实现一个近似方脉冲函数的神经网络(如下图所示),这是一个简单类型的阶梯函数。由于一系列阶梯函数可以逼近ℝn的一个紧子集上的任何连续函数,这将使我们了解为什么通用逼近定理成立。

左边的图表描述了一系列阶梯函数的连续函数近似;
右边的图表说明了一个单一的方脉冲阶梯函数
为了理解这个近似是如何工作的,从具有单标量输入x和sigmoid激活的单个单元开始。以下是该单元的可视化表示及其等效公式:

在下面的图中,可以看到在[-10,10]范围内输入不同的b和w值的公式曲线图。

在不同的w和b值下的神经元输出。网络输入x在x轴上表示
仔细检查公式和图,可以看到,sigmoid函数的陡度是由权重w决定的,函数在x轴上的平移是由公式t=-b/w决定的。我们讨论一下上图中的不同场景:
- 左上角的图表显示的是常规的sigmoid。
- 右上角的图表显示了一个较大的权值w将输入x放大到一个点,在这个点上单元输出类似于阈值激活。
- 左下角的图表显示了偏差b如何沿着x轴平移单元激活。
- 右下角的图表显示,我们可以以负权重w反转激活,并沿具有偏差b的x轴转换激活。
可以直观地看到,前面的图包含了方脉冲函数的所有成分。可以通过具有一个隐藏层的神经网络将不同的场景结合起来,隐藏层包含上述两个单元。下图显示了网络架构、单元的权重和偏差,以及网络产生的方脉冲函数:

下面是它的工作原理:
- 首先,顶部单元激活函数的上部阶梯激活并保持活跃。
- 底部单元随后激活函数的底部阶梯并保持活跃。由于输出层的权重相同但符号相反,所以隐藏单元的输出可以相互抵消。
- 输出层的权重决定了方脉冲矩形的高度。
这个网络的输出不是0,而是在(-5,5)区间内。因此,可以用类似的方式在隐藏层中添加更多的单元来近似额外的方脉冲。
现在我们已经熟悉了神经网络的结构,下面关注一下训练过程。