序言
在神经网络和机器学习的领域中,前馈网络(Feedforward Neural Network)是一种基础的神经网络架构,它通过信号向前传递(即从输入层到输出层)的方式来学习和解决问题。这里,我们将通过一个简单的例子——学习 XOR \text{XOR} XOR(异或)函数——来阐述前馈网络的基本工作原理和应用。
XOR \text{XOR} XOR函数是一个二元函数,当两个输入不同时返回1,相同时返回0。这个函数对于传统的线性模型来说是一个挑战,因为它不是一个线性可分的问题。然而,前馈网络凭借其非线性的激活函数和多层结构,能够学习并模拟这种非线性关系。
学习XOR实例
-
为了使用前馈网络的想法更加具体,我们首先从前馈网络充分发挥作用的一个简单例子说起:学习 XOR \text{XOR} XOR函数。
-
- XOR \text{XOR} XOR函数(”异或“逻辑)是两个二进制 x 1 x_1 x1和 x 2 x_2 x2的运算。当这些二进制值中恰好有一个为1时, XOR \text{XOR} XOR函数返回值为 1 1 1。其余情况下返回值为 0 0 0。
- XOR \text{XOR} XOR函数提供了我们想要学习的目标函数 y = f ∗ ( x ) y=f^\ast(\boldsymbol{x}) y=f∗(x)。
- 我们的模型给出了一个函数 y = f ( x ; θ ) y=f(\boldsymbol{x};\boldsymbol{\theta}) y=f(x;θ)并且我们的学习算法会不断调整参数 θ \boldsymbol{\theta} θ来使得 f f f尽可能接近 f ∗ f^\ast f∗。
-
在这个简单的例子中,我们不会关系统计泛化。我们希望网络在这四个点 X = { [ 0 , 0 ] ⊤ , [ 0 , 1 ] ⊤ , [ 1 , 0 ] ⊤ , [ 1 , 1 ] ⊤ } \mathbb{X}=\{[0,0]^\top,[0,1]^\top,[1,0]^\top,[1,1]^\top\} X={[0,0]⊤,[0,1]⊤,[1,0]⊤,[1,1]⊤}上表现正确。我们会用全部这四个点来训练我们的网络,唯一的挑战是拟合训练集。
-
我们可以把这个问题当作是回归问题,并使用均方误差损失函数。我们选择这个损失函数是为了尽可能简化本例中用到的数学。
-
在应用领域,对于二进制数据建模时, MSE \text{MSE} MSE通常并不是一个合适的损失函数。
-
为了对在整个训练集上的表现进行评估, MSE \text{MSE} MSE损失函数为:
J ( θ ) = 1 4 ∑ x ∈ X ( f ∗ ( x ) − f ( x ; θ ) ) 2 J(\boldsymbol{\theta})=\displaystyle\frac{1}{4}\sum\limits_{\boldsymbol{x}\in\mathbb{X}}(f^\ast(\boldsymbol{x})-f(\boldsymbol{x};\boldsymbol{\theta}))^2 J(θ)=41x∈X∑(f∗(x)−f(x;θ))2 -
我们现在必须要选择我们模型 f ( x ; θ ) f(\boldsymbol{x};\boldsymbol{\theta}) f(x;θ)的形式。假设选择一个线性模型, θ \boldsymbol{\theta} θ包含 w \boldsymbol{w} w和 b b b,那么我们的模型被定义成: f ( x ; w , b ) = x ⊤ w + b f(\boldsymbol{x};\boldsymbol{w},b)=\boldsymbol{x}^\top\boldsymbol{w}+b f(x;w,b)=x⊤w+b
-
我们可以用正规方程对 w \boldsymbol{w} w和 b b b最小化损失函数 J ( θ ) J(\boldsymbol{\theta}) J(θ),来得到一个封闭形式的解。
-
解正规方程以后,我们得到 w = 0 \boldsymbol{w}=0 w=0和 b = 1 2 b=\displaystyle\frac{1}{2} b=21。线性模型仅仅是在任意一点都输出 0.5 0.5 0.5。为什么会发生这种事情?图例1:演示了线性模型为什么用来表示 XOR \text{XOR} XOR函数。解决这个问题的其中一种方法是使用一个模型来学习一个不同的特征空间,在这个空间上线性模型能够表示这个解。
-
图例1:通过一个表示来解决 XOR \text{XOR} XOR问题。
-
说明:
- 图上的粗体数字标明了学得的函数必须在每个点输出的值。
- 左图:直接应用于原始输入的线性模型不能实现
XOR
\text{XOR}
XOR函数。
- 当 x 1 = 0 x_1=0 x1=0时,模型的输出必须随着 x 2 x_2 x2的增大而增大。
- 当 x 1 = 1 x_1=1 x1=1时,模型的输出必须随着 x 2 x_2 x2的增大而减小。
- 线性模型必须对 x 2 x_2 x2使用固定的系数 w 2 w_2 w2。因此,线性模型不能使用 x 1 x_1 x1的值来改变 x 2 x_2 x2的系数,从而不能解决这个问题。
- 右图:在由神经网络提取的特征表示的变换空间中,线性模型现在可以解决这个问题了。
- 在我们的示例解决方案中,输出必须为1的两个点折叠到了特征空间中的单个点。
- 换句话说,非线性特征将 x = [ 1 , 0 ] ⊤ \boldsymbol{x}=[1,0]^\top x=[1,0]⊤和 x = [ 0 , 1 ] ⊤ \boldsymbol{x}=[0,1]^\top x=[0,1]⊤都映射到了特征空间中的单个点 h = [ 1 , 0 ] ⊤ \boldsymbol{h}=[1,0]^\top h=[1,0]⊤。
- 线性模型现在可以将函数描述为 h 1 h_1 h1增大和 h 2 h_2 h2减小。
- 在该示例中,学习特征空间的动机仅仅是使得模型的能力更大,使得它可以拟合训练集。
- 在更现实的应用中,学习的表示也可以帮助模型泛化。
-
-
-
具体来说,我们这里引入一个非常简单的前馈神经网络,它有一层隐藏层并且隐藏层中包含两个单元。参见图例2中对该模型的解释。
-
图例2:使用两种不同样式绘制的前馈网络的示例
-
说明:
- 具体来说,这是我们用来解决 XOR \text{XOR} XOR问题的前馈网络。
- 它有单个隐藏层,包含两个单元。
- 左图在这种样式中:
- 我们将每个单元绘制为图中的一个节点。
- 这种风格是清楚而明确的,但对于比这个例子更大的网络,它可能会消耗太多的空间。
- 右图在这种样式中:
- 我们将表示每一层激活的整个向量绘制为图中的一个节点。
- 这种样式更加紧凑 。有时我们对图中的边使用参数名进行解释,这些参数是用来描述两层之间的关系。
- 这里,我们用矩阵 W \boldsymbol{W} W描述从 x \boldsymbol{x} x到 h \boldsymbol{h} h的映射,用向量 w \boldsymbol{w} w描述从 h \boldsymbol{h} h到 y y y的映射。
- 当标记这种图时,我们通常省略与每个层相关联的截距系数。
-
-
这个前馈网络有一个通过函数 f ( i ) ( x ; W , c ) f^{(i)}(\boldsymbol{x};\boldsymbol{W},\boldsymbol{c}) f(i)(x;W,c)计算得到的隐藏单元的向量 h \boldsymbol{h} h。
- 这些隐藏单元的值随后被用作第二层的输入。
- 第二层就是这个网络的输出层。输出层仍然是只是一个线性回归模型,只不过现在它作用于 h \boldsymbol{h} h而不是 x \boldsymbol{x} x。
- 网络现在包含链接在一起的两个函数: h = f ( i ) ( x ; W , c ) \boldsymbol{h}=f^{(i)}(\boldsymbol{x};\boldsymbol{W},\boldsymbol{c}) h=f(i)(x;W,c)和 y = f ( 2 ) ( h ; w , b ) y=f^{(2)}(\boldsymbol{h};\boldsymbol{w},b) y=f(2)(h;w,b),完整的模型是 f ( x ; W , c , w , b ) = f ( 2 ) ( f ( 1 ) ( x ) ) f(\boldsymbol{x};\boldsymbol{W},\boldsymbol{c},\boldsymbol{w},b)=f^{(2)}(f^{(1)}(\boldsymbol{x})) f(x;W,c,w,b)=f(2)(f(1)(x))
-
f
(
i
)
f^{(i)}
f(i)应该是哪种函数?
- 线性模型到目前为止表现不错,让 f ( i ) f^{(i)} f(i)也是线性的似乎很有诱惑力。不幸的是,如果 f ( i ) f^{(i)} f(i)是线性的,那么前馈网络作为一个整体对于输入仍然是线性的。
- 暂时忽略截距项,假设 f ( 1 ) ( x ) = W ⊤ x f^{(1)}(\boldsymbol{x})=\boldsymbol{W}^\top \boldsymbol{x} f(1)(x)=W⊤x并且 f ( 2 ) ( h ) = h ⊤ w f^{(2)}(\boldsymbol{h})=\boldsymbol{h}^\top \boldsymbol{w} f(2)(h)=h⊤w,那么 f ( x ) = w ⊤ W ⊤ x f(\boldsymbol{x})=\boldsymbol{w}^\top \boldsymbol{W}^\top \boldsymbol{x} f(x)=w⊤W⊤x。
- 我们可以将这个函数重新表示成 f ( x ) = x ⊤ w ′ f(\boldsymbol{x})=\boldsymbol{x}^\top \boldsymbol{w}^\prime f(x)=x⊤w′,其中 w ′ = W w \boldsymbol{w}^\prime=\boldsymbol{Ww} w′=Ww。
- 显然,我们必须用非线性函数来描述这个特征。大多数神经网络通过仿射变换之后紧跟着一个被称为激活函数的固定非线性函数来实现这个目标,其中仿射变换由学得的参数控制。
- 我们这里使用这种策略,定义 h = g ( W ⊤ x + c ) \boldsymbol{h}=g(\boldsymbol{W}^\top\boldsymbol{x}+\boldsymbol{c}) h=g(W⊤x+c),其中 W \boldsymbol{W} W是线性变化的权重矩阵, c \boldsymbol{c} c是偏置。
- 先前,为了描述线性回归模型,我们使用权重向量和一个标量的偏置参数来描述从输入向量到输出标量的仿射变化。
- 现在,因为我们描述的是向量 x \boldsymbol{x} x到向量 h \boldsymbol{h} h的仿射变换,所以我们需要一整个向量的偏置参数。
- 整流线性单元(rectified linear unit, ReLU)
- 激活函数 g g g通常选择对每个元素分别起作用的函数,有 h i = g ( x ⊤ W : , i + c i ) h_i=g(\boldsymbol{x}^\top\boldsymbol{W}_{:,i}+c_i) hi=g(x⊤W:,i+ci)。
- 在现代神经网络中,默认的推荐是使用由激活函数
g
(
z
)
=
max
{
0
,
z
}
g(z)=\max\{0,z\}
g(z)=max{0,z}定义的整流性单元(rectified linear unit, ReLU)或者成为
ReLU
\text{ReLU}
ReLU。 如下图例3所示。
-
说明:
- 该激活函数是被推荐用于大多数前馈神经网络的默认激活函数。
- 将此函数用于线性变换的输出将产生非线性变化。然而,函数仍然非常接近线性,在这种意义上它是具有两个线性部分的分段线性函数。
- 由于整流性单元几乎是线性的,因此它们保留了许多使得线性模型易于使用基于梯度的方法进行优化的属性。
- 它们还保留了许多使得线性模型能够泛化良好的属性。
- 计算机科学的一个公共原则是,我们可以从最小的组件构建复杂的系统。就像图灵机的内存只需要能够存储 0 0 0或 1 1 1的状态,我们可以从整流性函数构建一个通用函数逼近器。
-
我们现在可以指明我们的整个网络是: f ( x ; W , c , w , b ) = W ⊤ max { 0 , W ⊤ x + c } + b f(\boldsymbol{x};\boldsymbol{W},\boldsymbol{c},\boldsymbol{w},b)=\boldsymbol{W}^\top \max\{0,\boldsymbol{W}^\top\boldsymbol{x}+\boldsymbol{c}\}+b f(x;W,c,w,b)=W⊤max{0,W⊤x+c}+b。
- 现在可以给出 XOR \text{XOR} XOR问题的一个解。令 W = [ 1 1 1 1 ] \boldsymbol{W}=\begin{bmatrix}1 & 1\\1 & 1\end{bmatrix} W=[1111], c = [ 0 − 1 ] , w = [ 1 − 2 ] \boldsymbol{c}=\begin{bmatrix}0\\-1\end{bmatrix},\boldsymbol{w}=\begin{bmatrix}1\\-2\end{bmatrix} c=[0−1],w=[1−2], b = 0 b=0 b=0。
- 我们现在可以了解这个模型如何处理一批输入。令
X
\boldsymbol{X}
X表示设计矩阵,它包含二进制输入空间中全部的四个点,每个样例占一行,那么矩阵表示为:
X = [ 0 0 0 1 1 0 1 1 ] \boldsymbol{X}=\begin{bmatrix}0&0\\0&1\\1&0\\1&1\end{bmatrix} X= 00110101 - 神经网络的第一步是将输入矩阵乘以第一层的权重矩阵,得到 X W = [ 0 0 1 1 1 1 2 2 ] \boldsymbol{XW}=\begin{bmatrix}0&0\\1&1\\1&1\\2&2\end{bmatrix} XW= 01120112
- 然后,我们加上偏置向量 c \boldsymbol{c} c,得到 X W + c = [ 0 − 1 1 0 1 0 2 1 ] \boldsymbol{XW}+\boldsymbol{c}=\begin{bmatrix}0&-1\\1&0\\1&0\\2&1\end{bmatrix} XW+c= 0112−1001
- 在这个空间中,所有的样例都处在一条斜率为 1 1 1的直线上。当我们沿着这条直线移动时,输出需要从 0 0 0升到 1 1 1,然后再降回 0 0 0。线性模型不能实现这种函数。
- 为了用 h \boldsymbol{h} h对每个样例求值,我们使用整流线性变换: h = max { 0 , [ 0 − 1 1 0 1 0 2 1 ] } = [ 0 0 1 0 1 0 2 1 ] \boldsymbol{h}=\max\{0,\begin{bmatrix}0&-1\\1&0\\1&0\\2&1\end{bmatrix}\}=\begin{bmatrix}0&0\\1&0\\1&0\\2&1\end{bmatrix} h=max{0, 0112−1001 }= 01120001
- 这个变换改变了样例间的关系。它们不再处于同一条直线上了。如图例3所示,它们现在处在一个可以用线性模型解决的空间上。
- 我们最后乘以一个权重向量 w \boldsymbol{w} w,得到 h w = [ 0 0 1 0 1 0 2 1 ] [ 1 − 2 ] = [ 0 1 1 0 ] \boldsymbol{h}\boldsymbol{w}=\begin{bmatrix}0&0\\1&0\\1&0\\2&1\end{bmatrix}\begin{bmatrix}1\\-2\end{bmatrix}=\begin{bmatrix}0\\1\\1\\0\end{bmatrix} hw= 01120001 [1−2]= 0110
- 神经网络对这一批次中的每个样例都给出了正确的结果。
- 在这个例子中,我们简单地指明答案,然后说明它得到的误差为零。
-
结论
- 在实际情况中,可能会有数十亿的模型参数以及数十亿的训练样本,所以不能像我们这里做的那样进行简单地猜解。
- 与之相对的,基于梯度的优化算法可以找到一些参数使得产生的误差非常小。
- 我们这里给出的 XOR \text{XOR} XOR问题的解处在损失函数的全局最小点,所以梯度下降算法可以收敛到这一点。
- 梯度下降算法还可以找到 XOR \text{XOR} XOR问题一些其他的等价解。梯度下降算法的收敛点取决于参数的初始值。
- 在实践中,梯度下降通常不会找到像我们这里给出的那种干净的、容易理解的、整数值的解。
总结
通过学习 XOR \text{XOR} XOR函数,我们深刻理解了前馈网络在处理非线性问题上的强大能力。在这个例子中,我们构建了一个简单的前馈网络,通过调整网络中的权重和偏置项,网络逐渐学会了 XOR \text{XOR} XOR函数的输入输出映射关系。这不仅展示了前馈网络的学习能力,也为我们理解更复杂的神经网络模型提供了基础。
此外,这个例子还强调了非线性激活函数在前馈网络中的重要性。如果没有非线性激活函数,网络将只能学习线性关系,而无法处理 XOR \text{XOR} XOR这样的非线性问题。因此,在实际应用中,我们需要根据问题的性质选择合适的激活函数,以确保网络能够学习到复杂的数据模式和关系。