多层感知机

感知机模型是一种最为简单的前馈神经网络,但它同时又是卷积神经网络(CNN)和循环神经网络(RNN)的基础,因此这一章我们先从感知机模型开始学习。

20世纪中期,随着在达特茅斯会议上提出的人工智能概念,科学家们开始探索用数学和计算机技术来模拟人类思维过程的可能性,联结主义逐渐盛行。在这一背景下,美国心理学家弗兰克·罗森布拉特(Frank Rosenblatt)于1957年提出一种神经网络模型,通过自动调整权重进行学习来完成二分类的线性分类任务,这种模型被称为感知机(perceptron),并成为后续神经网络研究的基石。

MLP的结构与组成

感知机模型最初是受到神经元之间连接和信息传递过程启发来构造的,它主要由以下部分组成:

  • 输入层(x):接收输入数据,每个输入数据对应一个输入节点/神经元。

  • 中间隐藏层(hidden layer): 隐藏层位于输入层和输出层之间,负责对输入数据进行处理和特征提取。

  • 输出层(y):输出层是神经网络的最后一层,用于生成最终的预测结果。

这里需要注意的是,在神经网络中,层数通常是指网络中包含的隐藏层输出层的数量,而不包括输入层。例如,一个神经网络有1个输入层、3个隐藏层和1个输出层,那么这个神经网络通常被称为四层神经网络;而如果网络中有1个输入层、1个隐藏层和1个输出层,它就是一个两层神经网络。

10.1 神经网络的结构示意图

此外,神经网络还包括权重与偏置,激活函数,决策函数等,我们在下面将一一介绍。

权重和偏置

神经网络的层与层之间是通过网络权重(weight)来连接的,它们决定了输入信号在传递到下一层时的重要性,每一条连接都有一个对应的权重。

以图10.2为例,在神经网络中某一层中神经元的激活分别为a1,a2,...aKa_1,a_2,...a_K,对应的连接权重为w1,w2,...wKw_1,w_2,...w_K,经过加权后信号变为w1a1,w2a2,...wKaKw_1 a_1 , w_2 a_2, ... w_K a_K ,然后将这些加权输入相加得到总的输入信号:

z=w1a1+w2a2+...+wKaKz = w_1a_1 + w_2 a_2 +...+ w_K a_K

在更复杂的神经网络中,权重通常是用权重矩阵来表示各层之间的连接。比如,权重矩阵WW的元素 WijW_{ij}表示从上一层的第 jj个神经元到当前层第 ii 个神经元的连接权重。

偏置(bias)是另一个可调参数,它在加权求和的基础上增加了一个常数项,使得神经元的激活函数具有更多的灵活性。偏置相当于神经元的一个固定输入,当所有输入为零时,偏置决定了神经元的输出。这使得神经网络能够更好地适应数据,特别是在输入为零时确保神经元仍能激活。从数学上来看,加入偏置bb之后,总的输入信号变为:

z=w1a1+w2a2+...+wKaK+bz = w_1a_1 + w_2 a_2 +...+ w_K a_K +b

这个公式本质上就是一个线性映射(linear mapping),将输入向量RKR^K映射到实数 RR。在神经网络的全连接层中,输入层到隐藏层,或隐藏层到输出层的每一个映射都可以看作是线性映射。

神经网络的权重和偏置是重要的网络参数,会在训练过程中进行迭代和调整,使得网络能够更好的拟合数据。

图10.2 神经网络的结构

激活函数

上述的神经网络中每一层神经元都是前一层输入的线性组合,即使网络有多层,这些线性变换的组合仍然是一个线性函数。因此,整个神经网络只能表示输入和输出之间的线性关系。也就是说,在没有激活函数的情况下,增加网络的层数(深度)并不会增加其学习能力,网络的表达能力会受到很大限制,无法从数据中提取到有用的非线性特征。因此,我们引入一些激活函数来使得网络可以拟合非线性的数据模式。下面是几种常见的激活函数及特点:

  • Sigmoid:Sigmoid函数将输入从实数域映射到(0,1)(0,1)之间,它的表达式为:

σ(x)=11+ex\sigma (x) = \frac{1}{1+e^{-x}}

Sigmoid激活函数常用于二分类问题中,是一种简单的激活函数,但由于在远离0位置导数变小,因此容易导致梯度消失的问题,特别是在深层网络中,容易导致学习效率下降。

  • Tanh: Tanh函数将输入从实数映射到(1,1)(-1,1)之间,它的表达式为:

tanh(x)=exexex+extanh(x) = \frac{e^x-e^{-x}}{e^x+e^{-x}}

相比于Sigmoid函数,Tanh函数的输出是中心对称的,在某些问题中会更为合适,但同样存在梯度消失的问题。

  • ReLU:ReLU(Rectified Linear Unit) 函数是目前最为常用的激活函数,它将输入大于0的部分保留,小于或等于0的0的部分设为0,它的表达式为:

ReLU(x)=max(0,x)ReLU(x) = max(0,x)

ReLU的输出范围是[0,)[0, \infin),ReLU更接近于生态上神经元的发放行为,同时计算简单,缓解了梯度消失的问题,因此在深度神经网络中广为应用,但ReLU函数会导致“神经元死亡”问题,即一些神经元的输出恒为0,无法再更新。

  • Leaky ReLU:Leaky ReLU是ReLU的改进版本,当输入小于0时,输出为一个很小的负值,表达式为:

LeakyReLU(x)=max(αx,x)Leaky ReLU(x) = max(\alpha x,x)

其中,α\alpha是一个很小的正数,比如0.01,Leaky ReLU的输出范围是[αx,)[\alpha x, \infin),它允许负值输入有小的梯度,因此解决了ReLU的“神经元死亡”问题,但引入了一个额外的超参数α\alpha

激活函数在神经网络中扮演着至关重要的角色,通过引入非线性,使得神经网络能够学习和表达复杂的非线性关系。不同的激活函数有各自的优缺点,选择合适的激活函数可以显著提高模型的学习效果和性能。

图10.3 激活函数ReLU和Sigmoid

小知识:单层感知机与异或问题

单层感知机是一种没有隐藏层的神经网络模型,它只有一个输入层和一个输出层,因此它是最简单形式的神经网络。在单层感知机中,输入数据通过与权重相乘并加上偏置后直接送到输出层。输出层的激活函数(例如,阶跃函数或者Sigmoid)将输入信号转换为一个二分类结果(如0或1)。单层感知机只能解决线性可分的问题,例如将数据通过一条直线或一个平面分开。

XOR问题,也称为“异或问题”,是经典计算机科学和人工智能领域中广泛讨论的一个问题。XOR(eXclusive OR,异或)是一个基本的逻辑操作,其运算规则如下:

  • 当两个输入相同(即同为0或同为1)时,XOR输出0。

  • 当两个输入不同(即一个为0,一个为1)时,XOR输出1。

XOR的真值表如下:

输入 𝑥 1
输入 𝑥 2
输出 𝑦 = 𝑥 1 ⊕ 𝑥 2

0

0

0

0

1

1

1

0

1

1

1

0

将XOR操作视为一个二分类问题,输入 𝑥 1 x 1 ​ 和 𝑥 2 x 2 ​ 是二维平面上的坐标点,输出 𝑦 y 是对应的类别标签。如果将这四个点标注在二维平面上,会发现类别1的两个点 (0,1) 和 (1,0) 分别位于对角线上,而类别0的两个点 (0,0) 和 (1,1) 位于另一对角线上。XOR问题的关键在于它是线性不可分的。所谓线性不可分,意味着无法通过一条直线(在二维空间中)将这四个点分成两类。例如:无法画出一条直线同时将 (0,0) 和 (1,1) 分在一侧,而将 (0,1) 和 (1,0) 分在另一侧。

这意味着,XOR问题不能通过一个简单的线性模型(如单层感知机)来解决,因为单层感知机只能找到一个线性决策边界,而这种边界不足以将XOR问题中的数据点正确分类。

XOR问题的重要性在于,它明确展示了单层感知机的局限性。由于单层感知机只能处理线性可分的问题,XOR问题表明需要更复杂的模型结构,才能解决非线性分类任务。

这直接推动了多层感知机(MLP)的发展。通过引入至少一个隐藏层,MLP能够对输入数据进行非线性变换,使得模型可以在高维空间中找到一个线性可分的决策边界,从而正确解决像XOR这样的非线性问题。

具体来说,在多层感知机中,隐藏层通过将输入数据映射到更高维度的特征空间,可以在这个空间中实现原始输入数据的线性可分。这使得网络能够处理复杂的非线性关系,从而解决XOR问题,并在许多其他实际应用中表现出色。

决策函数Softmax

Softmax函数 是另一种常用的激活函数,特别是在多分类问题中,它通常用于神经网络的最后一层(输出层),将网络的输出转换为一个概率分布。Softmax函数的输出是一个概率向量,其中每个元素表示某个类别的概率,所有类别的概率之和为1。它的表达式为:

Softmax(zi)=ezij=1KezjSoftmax(z_i)=\frac{e^{z_i}}{\sum_{j=1}^{K}e^{z_j}}

其中,ziz_i​ 是输入向量 zz 的第 ii个分量, KK 是类别的总数,即输入向量的长度,输出 Softmax(zi)Softmax(z_i)是输入 ziz_i​ 所对应类别的概率。Softmax函数的主要作用是将任意实数向量转换为一个概率分布,这意味着它们可以直接解释为概率。这种归一化特性使Softmax非常适合分类问题。Softmax函数中使用了指数函数,放大了输入之间的差异。Softmax通常与交叉熵损失函数(Cross-Entropy Loss)结合使用,优化网络的参数以最大化真实类别的概率。Softmax函数在多分类问题中非常常用,例如图像分类(如MNIST手写数字识别)、文本分类(如情感分析)等。在自然语言处理任务中,Softmax也被用来计算词汇表中每个词的概率,帮助生成文本或进行序列预测。有时在强化学习中,Softmax也被用作选择策略的一部分,用于从多个行动中按概率选择一个行动。

MLP的应用举例: 分类任务

在这部分,我们将详细描述如何将线性变换、非线性激活函数以及Softmax决策函数组合在一起,构建一个用于图像分类的多层感知机(MLP)。假设我们要处理的任务是将一张 n×nn×n 像素的图片分类为猫、狗或鱼三个类别。

1. 输入层到隐藏层的线性变换

首先,假设输入图片已经被展平为一个向量 xx,其维度为 n2n^2。为了简单起见,假设输入层的维度为4,也就是一个长度为4的输入向量 x=[x1,x2,x3,x4]x=[x1,x2,x3,x4]。输入层经过一个线性变换后传递到隐藏层。这个线性变换由一个 4×44 \times 4的权重矩阵 WW 和一个长度为4的偏置向量b1b_1组成。线性变换的过程如下:

z1=W1x+b1z_1 = W^1 x + b_1

其中,W1W_1 是一个 4×44 \times 4 的矩阵,表示从输入层到隐藏层的权重,b1b1是隐藏层的偏置向量。

2. 隐藏层的非线性激活

在得到线性变换的结果 z1z_1后,我们将其通过一个非线性激活函数。这里,我们选择常用的ReLU(Rectified Linear Unit)激活函数。激活后的隐藏层输出hh 计算如下:

h=ReLU(z1)=ReLU(W1x+b1)h=ReLU(z_1)=ReLU(W^1x+b_1)

3. 隐藏层到输出层的线性变换

激活函数的输出hh 接着通过另一个线性变换传递到输出层。这个线性变换由一个 4×34 \times 3的权重矩阵 W2W_2和一个长度为3的偏置向量b2 b2组成。线性变换的计算如下:

z2=W2h+b2z_2=W^2h+b_2

这里,W2W2是一个 4×34 \times 3 的矩阵,将隐藏层的输出映射到三个输出节点,分别对应 ”猫、狗、鱼“这三类。z2z_2是输出层的未激活输出,通常称为“logits”。

4. 输出层的Softmax决策

最后,我们将输出层的logits通过Softmax函数进行处理,得到每个类别的预测概率。Softmax函数将 z2z_2中的每个分量 z2iz_{2i}转换为一个概率值pi p_i

p(i)=ez2ij=13ez2ip(i)=\frac{e^{z_{2i}}}{\sum_{j=1}^{3}e^{z_{2i}}}

其中,z2iz_{2i}​ 表示输出层中第 ii 个节点的值,p(i)p(i)表示模型预测输入图片属于第 ii 类(猫、狗或鱼)的概率。

通过结合线性变换、非线性激活函数和Softmax决策函数,构建了一个能够对图像进行分类的多层感知机(MLP)。这个简单的例子展示了如何通过层层变换,将输入数据逐步映射到最终的输出类别,并从中学习到有效的分类决策规则。多层感知机正是通过这些步骤,成功应用于图像分类、文本分类等各种实际问题中。

网络训练

在我们构建和设计好神经网络之后,就可以进行前馈计算,网络会根据我们的输入和默认的随机权重给出输出的结果,但没有经过训练的网络通常是随机/错误的,我们需要对网络进行训练,使其能够从数据中学习并进行准确的预测。这里我们需要学习几个重要的概念。

损失函数(loss function)

在前向传播过程中,输入数据依次通过网络的各层,经过线性变换、激活函数等操作,最终生成输出结果。对于每一个输入数据,网络会计算出一个对应的输出(也称为预测值)。在前向传播的最后,网络的输出与实际的目标值(标签)进行对比,计算出损失值(loss)。它度量模型的预测结果与实际目标值之间的差异,即模型误差的大小。我们训练网络也就是最小化损失函数的值。因此,损失函数在训练过程中起着至关重要的作用。

根据不同的任务类型(如回归、分类等),我们可以选择不同的损失函数。以下是几种常见的损失函数:

  • 均方误差(Mean Squared Error, MSE): MSE是回归任务中最常用的损失函数之一,它计算预测值与实际值之间的平方差的平均值。公式为:

MSE=1ni=1n(yiyi^)2MSE = \frac{1}{n} \sum_{i=1}^{n}(y_i-\hat{y_i})^2

其中,yiy_i 是第 ii个样本的实际值,yi^\hat{y_i}​ 是模型的预测值,nn是样本数量。MSE对误差的平方进行了放大,使得较大的误差对损失的影响更显著。

  • 平均绝对误差(Mean Absolute Error, MAE): MAE是另一个常用于回归任务的损失函数,它计算预测值与实际值之间的绝对差的平均值。公式为:

MAE=1ni=1nyiyi^MAE = \frac{1}{n} \sum_{i=1}^{n}|y_i-\hat{y_i}|

MAE对每个误差值进行线性处理,相对于MSE,MAE对异常值不敏感。

  • 交叉熵损失(Cross-Entropy Loss): 交叉熵损失是分类任务中最常用的损失函数,特别是多分类任务。它衡量了真实类别分布与预测类别分布之间的差异。对于二分类问题,交叉熵损失函数的公式为:

Cross EentropyLoss=1ni=1n[yilog(yi^)+(1yi)log(1yi^)]Cross\ Eentropy-Loss = -\frac{1}{n}\sum_{i=1}^{n}[y_i log(\hat{y_i})+(1-y_i)log(1-\hat{y_i})]

其中,yiy_i​ 是实际标签(0或1),yi^\hat{y_i}是预测概率。对于多分类问题,交叉熵损失可以扩展为:

Cross EntropyLoss=c=1Myclog(pc)Cross \ Entropy-Loss = -\sum_{c=1}^{M} y_c log(p_c)

其中,MM 是类别数量,如果样本真实类别等于ycy_c​ 为1,否则为0;pcp_c是模型预测的类别cc的概率。

以我们猫/狗/鱼的三分类任务为例,经过前馈计算以后,模型预测其为猫/狗/鱼的概率分别是𝑝=[0.7,0.2,0.1]𝑝=[0.7, 0.2, 0.1], 而这个图片的真实标签是猫,那么交叉熵损失就是

crossentropy  loss=(1log(0.7)+0log(0.2)+0log(0.1))=log(0.7)cross-entropy \ \ loss = -(1*log(0.7)+0*log(0.2)+0*log(0.1))=-log(0.7)

在真实的模型训练中,往往有很多样本,那么总体的损失函数是所有样本的损失求和。

损失函数的选择直接影响模型的性能和训练效果。不同类型的任务需要不同的损失函数:回归任务中MSE和MAE是最常见的选择。MSE对较大的误差更为敏感,而MAE则对异常值更具鲁棒性。分类任务中交叉熵损失是最常用的,特别是在与Softmax结合使用时。对于二分类问题,可以选择二元交叉熵损失,对于多分类问题,选择多类交叉熵损失。

误差反向传播

在计算出损失函数之后,我们要如何更新网络权重呢?这里就有一个重要概念——误差反向传播。反向传播是网络根据损失值来更新网络参数(如权重和偏置)的过程。通过反向传播算法,损失值会从输出层逐层传递回隐藏层和输入层,计算每个参数对总损失的贡献,即参数的梯度。通过这些梯度,网络可以调整各层的权重和偏置,使得下一次前向传播中的损失值减少。

反向传播的数学基础是链式法则,通过逐层计算损失函数相对于每个参数的偏导数,更新网络的权重和偏置。该过程反复进行,直到损失函数收敛到一个较小的值。下面我们以一个例子来推导反向传播。

简化起见,我们考虑如下的二分类的神经网络,网络输出为1代表猫, 0代表狗。

图10.4 误差反向传播示例

这个网络是一个两层的全连接网络,输入为二维向量 xx,输出为概率向量 oo。网络结构包括:

  • 输入层:包含2个神经元,对应输入向量 x=[x1,x2]x=[x1,x2]

  • 隐藏层:包含2个神经元,权重矩阵为 W1W^1,是一个2×22 \times 2 的矩阵,激活函数为 ReLU。

  • 输出层:包含2个神经元,权重矩阵为 W2W^2,是一个2×22 \times 2 的矩阵,激活函数为 Softmax。

这个网络中,共有8个参数,分别是隐藏层的权重矩阵W1W^1和输出层的权重矩阵W2W^2

假设我们使用交叉熵损失函数来度量模型输出与真实标签 yy之间的差异。反向传播的目标是计算损失函数 LL 对网络参数(W1 W ^1W2W ^2 )的梯度。我们从输出层开始,逐层向后推导梯度。

对于图10.4中的例子,交叉熵损失为

L=j=1Nyjlog(oj)=1log(o1)0log(o2)L = -\sum_{j=1}^{N} y_j log(o_j)=-1 * log(o_1) - 0 * log(o_2)

交叉熵损失函数对输出 oo 的偏导数为:

Lo1=1o1, Lo2=0\frac{\partial L}{\partial o_1}=\frac{1}{o_1},\ \frac{\partial L}{\partial o_2}=0

然后,我们继续计算损失函数LL对激活值 z2z^2 的偏导数,根据链式法则:

Lz2=Lo.oz2\frac{\partial L}{\partial z^2}=\frac{\partial L}{\partial o} . \frac{\partial o}{\partial z^2}

其中oz2\frac{\partial o}{\partial z^2}可根据Softmax函数的定义得到:

o1z12=o1(1o1), o1z22=o1o2\frac{\partial o_1}{\partial z_1^2} = o_1(1-o_1),\ \frac{\partial o_1}{\partial z_2^2}=-o_1o_2

oz2\frac{\partial o}{\partial z^2}逻辑上是一个2×22\times 2的矩阵,但考虑在这个例子中,我们的label是(1,0)(1,0),在前一步的求导过程中只有第一列是非0列,因此可以省略了o2z2\frac{\partial o_2}{\partial z^2}

结合两部分,可得:

Lz2=(1o1,0)(o1o120o1o20)=(o11,o2)\frac{\partial L}{\partial z^2}=(-\frac{1}{o_1},0) *\left( \begin{matrix} o_1 - o_1^2 & 0 \\ -o_1 *o_2& 0 \end{matrix} \right)=(o_1-1,o_2)

我们继续运用链式法则对参数w12w_1^2求导可得:

Lw112=Lo1.o1z12.z12w112=1o1.(o1o12).h\frac{\partial L}{\partial w^2_{11}}=\frac{\partial L}{\partial o_1} . \frac{\partial o_1}{\partial z^2_1}.\frac{\partial z_1^2}{\partial w_{11}^2}=-\frac{1}{o_1}.(o_1-o_1^2).h

训练网络的目的是尽可能的减小loss,所以我们根据梯度来更新网络中的权重参数:

w112=w112α.Lw112w_{11}^2=w_{11}^2-\alpha . \frac{\partial L}{\partial w_{11}^2}

推广到更一般的情况,对于权重矩阵中的元素WijW_{ij}有:

Wij2:=Wij2α.LWij2W_{ij}^2:=W_{ij}^2-\alpha . \frac{\partial L}{\partial W_{ij}^2}

其中, α\alpha 是学习率,控制参数更新的步伐大小。

同理,我们可以继续将损失向后传播,例如来更新参数w111w_{11}^1

Lw112=Lo1.o1z12.z12h.hz1z1w111\frac{\partial L}{\partial w^2_{11}}=\frac{\partial L}{\partial o_1} . \frac{\partial o_1}{\partial z^2_1}.\frac{\partial z_1^2}{\partial h}.\frac{\partial h}{\partial z^1}\frac{\partial z^1}{\partial w_{11}^1}

通过以上步骤,我们从输出层开始,逐层计算损失函数相对于每个参数的梯度,并最终利用这些梯度来更新参数。反向传播算法提供了一种高效的方式,使得我们能够在复杂的神经网络中训练大规模的参数。这一过程的本质是利用链式法则将损失函数的误差向后传播,从而优化整个网络的表现。通过不断迭代,反向传播使得神经网络能够在给定数据集上逐步提高其预测准确率。

批次与超参数

以我们上述猫狗分类任务为例,假如我们共有N个训练样本,如100,000张图片,理论上我们可以每次输入一张图片,然后计算loss,再根据backpropagation来调整参数,但是单张图片计算的loss的噪音很大,可能在网络训练的初级很难找到合适的优化方向;也可以把所有图片都输入,然后总体计算一个loss,这样的loss计算非常稳定,但是需要所有图片输入才更新一次,网络训练太慢。一个折衷的办法是将样本按批次(batch)进行训练。每次只输入一部分的图片,比如50张,计算loss并更新模型参数。按照batch输入的方式,把所有的训练集图片遍历一遍,叫一个epoch。例如一共10w张图片,一个batch为50张,那么1个epoch有2000个batch。

因此,Batch 指的是在训练过程中,一次前向传播和反向传播所使用的数据样本的集合。常见的batch大小如32、64、128等。小的batch(例如32或64)可以更频繁地更新模型参数,使得训练更加灵活,可能更容易跳出局部最小值。但是,训练过程中的噪声较大,收敛速度可能较慢。大的batch(例如128或256)可以更稳定地更新模型参数,因为每次更新时使用的数据更多。然而可能需要更多的内存,且在某些情况下可能会导致模型陷入局部最小值,影响训练效果。

Epoch 指的是完整遍历整个训练数据集一次的过程。一个Epoch意味着模型在整个训练集上进行了一次完整的训练。选择合适的Epoch数量是关键,如果Epoch过少,模型可能还未充分学习,导致欠拟合(Underfitting);如果Epoch过多,模型可能会过度拟合训练数据,导致泛化能力下降(过拟合)。通常我们会绘制模型在训练集和验证集上的损失值或准确率随epoch数增加的变化曲线(学习曲线),来分析模型的学习情况,确定合适的epoch数。

最后,我们还需要了解的一个概念是超参数。简单来理解,超参数就是模型训练前设置的参数,它们不会在训练过程中更新,而是由用户预先定义。换句话说,超参数并不是模型参数,而是训练模型所需要的一些参数。

常见的超参数包括:

  • 学习率(Learning Rate):学习率决定了每次梯度下降更新的步伐大小。学习率过大可能导致训练过程不稳定,模型无法收敛;学习率过小则可能导致训练过程过于缓慢,难以达到全局最优。

  • 批量大小(Batch Size):如前文所述,批量大小影响每次参数更新时使用的数据量。

  • 正则化参数:正则化方法(如L1正则化、L2正则化、Dropout等)用于防止模型过拟合。正则化参数控制正则化的强度。

  • 优化算法:选择合适的优化算法(如SGD、Adam、RMSprop等)也是超参数的一部分,不同的优化算法适用于不同的任务和数据集。

在这一节中,我们介绍了多层感知机的结构和基本原理,引入了损失函数并推导了误差反向传播,这一部分学习内容将为我们学习卷积神经网络和循环神经网络打下基础。

最后更新于