多层感知器(MLP)是一种前馈人工神经网络,它拥有输入层、隐藏层(至少1层)和输出层。如果隐藏层超过1个,则又称为深度人工神经网络。
多层感知机(Multilayer Perceptron,MLP)是神经网络(Neural Network)的一种特殊类型。
- MLP是一种前馈神经网络,它由至少三层节点组成:输入层、一个或多个隐藏层以及输出层。
- 在标准的MLP中,每一层的节点都是全连接的,即每一层的所有节点都与下一层的所有节点相连。
- MLP中的节点(或神经元)通常使用非线性激活函数,允许网络学习复杂的函数映射。
- MLP通常使用梯度下降和反向传播算法来训练,调整网络权重以最小化损失函数。
多层感知器(MLP)工作机制
其实大多数线性问题,我们可以用更简单的线性回归(可以简单的理解为只有输入层和输出层的简化神经网络)来解决,但线性意味着单调假设:任何特征的增大都会导致模型输出的增大(如果对应的权重为正), 或者导致模型输出的减小(如果对应的权重为负)。
- 有时这是有道理的。例如,如果我们试图预测一个人是否会偿还贷款。 我们可以认为,在其他条件不变的情况下, 收入较高的申请人比收入较低的申请人更有可能偿还贷款。 但是,虽然收入与还款概率存在单调性,但它们不是线性相关的。 收入从0增加到5万,可能比从100万增加到105万带来更大的还款可能性。 处理这一问题的一种方法是对我们的数据进行预处理, 使线性变得更合理,如使用收入的对数作为我们的特征。
- 然而我们可以很容易找出违反单调性的例子。 例如,我们想要根据体温预测死亡率。 对体温高于37摄氏度的人来说,温度越高风险越大。 然而,对体温低于37摄氏度的人来说,温度越高风险就越低。 在这种情况下,我们也可以通过一些巧妙的预处理来解决问题。 例如,我们可以使用与37摄氏度的距离作为特征。
- 但是,如何对猫和狗的图像进行分类呢? 增加位置处像素的强度是否总是增加(或降低)图像描绘狗的似然? 对线性模型的依赖对应于一个隐含的假设, 即区分猫和狗的唯一要求是评估单个像素的强度。 在一个倒置图像后依然保留类别的世界里,这种方法注定会失败。这里的线性很荒谬, 而且我们难以通过简单的预处理来解决这个问题。 这是因为任何像素的重要性都以复杂的方式取决于该像素的上下文(周围像素的值)。 我们的数据可能会有一种表示,这种表示会考虑到我们在特征之间的相关交互作用。 在此表示的基础上建立一个线性模型可能会是合适的, 但我们不知道如何手动计算这么一种表示。 对于深度神经 网络,我们使用观测数据来联合学习隐藏层表示和应用于该表示的线性预测器。
多层感知机结构
所以这时候,我们可以在网络中加入一个或多个隐藏层来克服线性模型的限制, 使其能处理更普遍的函数关系类型。 要做到这一点,最简单的方法是将许多全连接层堆叠在一起。 每一层都输出到上面的层,直到生成最后的输出。 我们可以把前 $ L-1 $层看作标识,把最后一层看作线性预测器。 这种架构通常称为多层感知机(multilayer perceptron),通常缩写为MLP。 下面,我们以图的方式描述了多层感知机。
借助隐藏层的存在,从而可以使多层感知机可以实现复杂的非线性映射。
为了便于理解,我们可以带入一个简单的示例:
产品经理向我们剔除一个需求,问我们能不能做,那么一个简化的多层感知机模型示意如下:
输入层会有很多实际的现状情况,对应隐藏层,其实就是我们基于不同的已知信息(输入层)按不同权重、偏置来计算隐藏层的输出(每个节点可以抽象为我们需要考虑的一个特定方面,每个方面都会不同程度上决定我们最终是否进行开发),然后通过输出层,综合考虑隐藏层(各个方向的结论),得到最终的输出。
从这个示例,我们其实可以看到,针对每个输入的信息,我们都可以进行加权判定生成隐藏层,在多隐藏层的情况下,我们也可以对数据进行多轮加权判定,从而理论上可以实现基于已知输入的所有逻辑类型。
需要注意的时,具有全连接层的多层感知机的参数开销可能会高得令人望而却步。 即使在不改变输入或输出大小的情况下, 可能在参数节约和模型有效性之间进行权衡。
激活函数
如前文提到的,我们引入神经网络,引入隐藏层,实际是为了解决线性模型不能解决的复杂问题,实现非线性变换。使得神经网络能够学习和逼近复杂的函数映射。而这里实现非线性变换,就是依靠激活函数来实现的,对特定的输入使用激活函数进行处理,形成隐藏层数据。
激活函数接收神经元的加权输入和偏置之和作为输入,然后输出一个经过某种非线性变换的值。这种非线性变换允许神经网络在多层结构中堆叠时,捕捉到数据中的复杂模式和层次结构。
激活函数在神经网络中至关重要,它们为神经网络引入非线性,使网络能够学习和逼近复杂的函数映射。激活函数都是非线性的,而我们在计算激活值时使用的都是线性运算,引入激活函数能让我们在后续的计算中逼近任何的非线性函数,从而使神经网络有更好的普适性。
Sigmoid函数
- 公式:
f(x) = 1 / (1 + e^-x) - 应用场景: 早期神经网络中常用,尤其适用于输出层,当需要输出值在0到1之间时。
- 缺点: 易发生梯度消失,计算效率不高。
tanh函数
- 公式:
f(x) = tanh(x) - 应用场景: 类似于Sigmoid函数,但输出范围在-1到1之间,有助于网络收敛。
- 缺点: 存在梯度消失问题。
ReLU函数 (Rectified Linear Unit)
- 公式:
f(x) = max(0, x) - 应用场景: 广泛用于深层神经网络的隐藏层,特别是在卷积神经网络中。
- 优点: 计算简单,缓解梯度消失问题。
- 缺点: 对于负输入,梯度为0,可能导致神经元“死亡”。
Leaky ReLU函数
- 公式:
f(x) = max(alpha * x, x),其中alpha是一个小的正数。 - 应用场景: 解决ReLU函数在负数区域梯度为0的问题。
- 优点: 避免神经元“死亡”。
ELU函数 (Exponential Linear Units)
- 公式:
f(x) = x如果x > 0;f(x) = alpha * (e^x - 1)如果x <= 0 - 应用场景: 类似于Leaky ReLU,但输出均值更接近于0。
- 优点: 输出均值接近0,有助于梯度传播。
SELU函数 (Scaled Exponential Linear Units)
- 公式:
f(x) = lambda * x如果x > 0;f(x) = lambda * (alpha * (e^x - 1))如果x <= 0 - 应用场景: 设计用于自动归一化网络。
- 优点: 使网络自动达到归一化状态。
Softmax函数
- 公式:
f(x_i) = e^(x_i) / sum(e^(x_j)),对输出层,将向量转换为概率分布。 - 应用场景: 主要用于多分类问题的输出层。
选择激活函数时,需要根据模型的具体需求、数据特性和任务类型来决定。例如,对于回归任务,输出层可能不需要激活函数(或使用线性激活函数)。而在隐藏层中,ReLU和它的变体因其计算效率和梯度传播的优势而广泛使用。
权重与偏置的调整
在多层感知机(MLP)中,权重(weights)和偏置(biases)是神经网络模型中的关键参数,它们在神经元的计算过程中起着核心作用。下面分别解释这两个概念:
权重(Weights)
权重代表了神经网络中神经元之间的连接强度。每个连接都有一个对应的权重值,这个值决定了输入信号对于后续神经元输出的影响程度。在数学上,权重通常表示为矩阵,用于将前一层神经元的输出与当前层神经元的输入相连接。
- 当权重较大时,意味着前一层的神经元对该神经元的输出有较大的影响。
- 当权重较小时,意味着前一层神经元的影响较小,或者可以说该神经元对于当前神经元的输出贡献不大。
- 权重的学习和调整是通过训练过程中的反向传播算法完成的,目的是最小化网络输出与期望输出之间的差异(损失函数)。
偏置(Biases)
偏置是附加到每个神经元上的一个额外参数,它不依赖于任何输入,而是在神经元的激活计算中始终存在。偏置的作用类似于数学方程中的截距,它允许神经元的激活阈值进行调整,从而影响神经元何时被激活。
- 偏置允许每个神经元的激活函数在不考虑输入的情况下也能产生输出。如果没有偏置,神经元只能通过输入信号的组合来激活,这会限制模型的灵活性。
- 调整偏置值可以让神经元即使在输入为零时也能产生非零输出,或者改变神经元被激活的阈值,这对于学习更复杂的决策边界是非常重要的。
- 偏置的值也是通过训练过程进行学习和更新的,以优化网络的整体性能。
在MLP中,每个神经元的净输入(即神经元的加权输入总和加上偏置)通过激活函数进行转换,产生该神经元的最终输出。这个过程可以表示为:
$step1: z=Wx+b $
$step2: a=f(z) $z 是神经元的净输入,
W 是权重矩阵,
x 是输入向量,
b 是偏置向量,
a 是经过激活函数 $f(z)$ 转换后的输出。
权重和偏置的优化是神经网络训练的核心,机器学习的过程其实就是模型根据提供的训练数据不断调整和优化权重和偏置的过程。
参数性能的度量:损失函数和代价函数
我们想要让模型自己基于数据进行训练学习,寻找最优的权重和偏置,以使得模型在训练数据上的表现达到最好的效果。有一个前提,就是我们首先须能够评估(量化)每个不同的权重或偏置的表现如何,因此为了评估不同参数对应的性能表现,我们引入了损失函数(对单个样本而言)、代价函数(对训练集所有样本的损失函数值的平均函数)。
损失函数就是给矫正参数提供数据支撑的,损失函数因不同的算法而异,我们可以根据项目需求进行选择。但是无论是哪种损失函数,它都要符合一个原则:当网络能对图像进行正确分类时,损失函数值要比较小,偏差的越大,损失值越大。
通过损失函数的构建,我们完成了对要解决问题的转换和抽象化,现在我们要解决的问题是:如何找到一个参数组合,使得训练集上的损失函数值最小。
参数调整的方法
通过损失函数,我们可以评估一套参数表现的好和坏,但是我们的目的,是找到最优参数,针对多层感知机的特殊性(是一种全链接的神经网络),我们不难发现随着隐藏层的增加和隐藏节点的增加,模型的参数量会急速增加,而每个参数都可能是从(-∞,+∞)的庞大范围,参数组合更是无法枚举的量级。所以显然我们还需要一些方法/技巧来帮助我们更合理的对参数进行快速优化,找出最优解(而不是随机抽签,或者遍历宇宙间的所有可能┑( ̄Д  ̄)┍)。
目前比较常用的方法有:
梯度下降法:
梯度下降法是一种迭代的方法,通过逐步更新参数向量来逼近目标函数的最小值。其核心思想是通过梯度下降的方式逐步更新参数向量,使目标函数的值逐步减小。
为了方便理解,我们在这先介绍两个概念,梯度和学习率,分别决定我们更新参数的方向和步长。
- 梯度: 梯度的数学定义:梯度是一个向量(或矢量),用于表示某一函数在该点处的方向导数沿着该方向取得最大值。简言之,梯度指明了函数在该点处变化最快的方向和变化率。
- 学习率:学习率是梯度下降法的一个超参数,它控制着每次调整参数的大小, learning rate 越大,每次调整的参数越大,收敛速度越快,但 learning rate 过大可能会导致梯度下降过程不稳定, learning rate 过小可能会导致梯度下降过程收敛速度过慢。
更直观的讲,梯度可以被想象为多维空间中的“斜率指南”,它告诉我们函数在哪个方向上增长(或下降)最快。下面我们分别借助一元函数(方向是线的两面)、二元函数(方向是一个发散的平面)更好的理解梯度的概念。
- 先抛开自变量众多的代价函数,我们先看看如何求解一元函数的最小值,其方法在任意一本微积分教材上应该都有:计算导数为0的点,确定极小值,计算极小值中的最小值。
但我们本身使用神经网络就是为了拟合一些复杂函数,这类函数有些可能求导本身可能就已经非常困难了,而同时这些复杂网络中,我们要处理的节点数量成千上万。更巧妙的方法是:随便挑一个输入值,然后判断,向左走还是向右走函数值才会变小呢?如果随机的这一点处斜率为正,向左走一点能让函数值变小;如果斜率为负那么就向右走一点。走的时候还需要注意:斜率越平缓时走的每一步应该越来越小,这样可以保证不会“走过头”而越过极小值点。(但我们需要注意:极小值点不一定是最小值点,神经网络也会遇到高等数学解题中同样的问题。)
- 拓展到二元函数:类比一元函数,在二元函数的图像中,我们参数调整的范围从左右线性编程了一个平面,这时候我们要思考的应该是“哪个方向下山最快?”,尽管尚未接触二元函数知识,但我们知道,按梯度的方向走,函数值增长的最快,那么按梯度的反方向,函数值(对应损失函数)就减少的最快,而且梯度向量的长度代表了这个最陡的斜坡到底有多陡。

这样我们就得到了一种让函数值最小的算法:
计算梯度 → 按梯度反方向调整自变量 → 循环,这对多个自变量为输入的代价函数也是一样,将所有输入作为n维的列向量并计算负梯度并加在列向量上就能计算出调整后的神经网络参数。 - 扩展到多元函数,我们只需要计算出每个参数的偏导数,然后所有参数的偏导共同构成了我们的梯度向量$ ∇f=({∂f \over ∂x},{∂f \over ∂y})$,这个梯度向量在几何上表示了函数在该点处增长最快的方向(即函数值/损失函数 增加最快的方向),而梯度的负方向则是指向函数值减小最快的方向,这正是梯度下降法所利用的性质。然后按照梯度反方向调整参数,就可以得到一个梯度下降法。
需要注意的是,代价函数是对训练集而言,也就是很可能出现这样一种情况:随机的参数在特定输入上得到了正确答案,但训练后的参数反而给出了错误的答案,这是因为上述梯度下降的过程是针对所有样本而言的,训练后的参数对所有样本得到的总体结果会更好一些。
几种应用类型:
- 批量梯度下降法,是梯度下降法最常用的形式,具体做法也就是在更新参数时使用所有的样本来进行更新。由于我们有m个样本,这里求梯度的时候就用了所有m个样本的梯度数据。
- 随机梯度下降法,其实和批量梯度下降法原理类似,区别在与求梯度时没有用所有的m个样本的数据,而是仅仅选取一个样本j来求梯度。对应的更新公式是:
- 小批量梯度下降法,是批量梯度下降法和随机梯度下降法的折衷,也就是对于m个样本,我们采用x个样本来迭代,$1<x<m$。一般可以取$x=10$,当然根据样本的数据,可以调整这个x的值。
随机梯度下降法和批量梯度下降法是两个极端,一个采用所有数据来梯度下降,一个用一个样本来梯度下降。自然各自的优缺点都非常突出。对于训练速度来说,随机梯度下降法由于每次仅仅采用一个样本来迭代,训练速度很快,而批量梯度下降法在样本量很大的时候,训练速度不能让人满意。对于准确度来说,随机梯度下降法用于仅仅用一个样本决定梯度方向,导致解很有可能不是最优。对于收敛速度来说,由于随机梯度下降法一次迭代一个样本,导致迭代方向变化很大,不能很快的收敛到局部最优解。
牛顿法
而我们要寻找损失函数的极值,除了像梯度下降法一样根据斜率和学习率进行迭代遍历(效率会收到学习率的影响,同时最终精度也会受到学习率的影响),还可以借助目标函数($f(x)$)的导数($f’(x)$)来更快地找到目标函数的最小值,也就是寻找($f’(x)=0$)的点。这时候,我们又进一步将问题转换为求解$f’(x)=0$的问题。具体步骤如下:
- 选择一个接近函数 $f(x)$零点的 $x_0$,计算相应的 $f (x0)$ 和切线斜率$f’(x_0)$(这里$f’$ 表示函数 $f$ 的导数)。然后我们计算穿过点$(x_0, f(x_0))$ 并且斜率为$f’(x_0)$的直线和 x 轴的交点的x坐标,也就是求如下方程的解:
$$xf’(x_0)+f(x_0)-x_0f’(x_0)=0 等价于 x_1=x_0-{f(x_0)\over f’(x_0)}$$ - 我们将新求得的点的 $x$ 坐标命名为$x_1$,通常$x_1$会比$x_0$更接近方程$f(x) =0$的解。因此我们现在可以利用$x_1$开始下一轮迭代。迭代公式可化简为如下所示:
$$x_{n+1}=x_n-{f(x_n)\over f’(x_n)}$$ - 已经证明,如果 $f’$ 是连续的,并且待求的零点$x$是孤立的,那么在零点x周围存在一个区域,只要初始值$x0$位于这个邻近区域内,那么牛顿法必定收敛。 并且,如果 $f’(x)$不为0, 那么牛顿法将具有平方收敛的性能. 粗略的说,这意味着每迭代一次,牛顿法结果的有效数字将增加一倍。
由于牛顿法是基于当前位置的切线来确定下一次的位置,所以牛顿法又被很形象地称为是”切线法”。牛顿法的搜索路径(二维情况)如下图所示:
下图为一个牛顿法执行过程的例子。
牛顿法是一种高效的方法,通过使用目标函数的二阶导数来更快地找到目标函数的最小值。对于初始位点的需求没有梯度下降法这么高,同时由于具有收敛性,所以经过足够迭代我们总可以获取所需精度的结果,而不需要依赖于学习率。