神经网络(二)——多层感知机(Multilayer Perceptron)

在现实世界中有很多数据无法通过线性变换来表示,可以通过在网络中加入一个或多个隐藏层来克服线性模型的限制, 使其能处理更普遍的函数关系类型。最简单的方法是将许多全连接层堆叠在一起,每一层都输出到上面的层,直到生成最后的输出。可以把前层看作表示,把最后一层看作线性预测器。这种架构通常称为多层感知机(multilayer perceptron),通常缩写为MLP。一个单隐藏层的多层感知机,具有5个隐藏单元:

这个多层感知机有4个输入,3个输出,其隐藏层包含5个隐藏单元。 输入层不涉及任何计算,因此使用此网络产生输出只需要实现隐藏层和输出层的计算。 因此,这个多层感知机中的层数为2。多层感知机在输出层和输入层之间增加一个或多个全连接隐藏层,并通过激活函数转换隐藏层的输出。

一、激活函数

激活函数(activation function)通过计算加权和,并加上偏置来确定神经元是否应该被激活,它们将输入信号转换为输出的可微运算。大多数激活函数都是非线性的。

1.1 ReLU函数

最受欢迎的激活函数是修正线性单元(Rectified linear unit,ReLU),因为它实现简单,同时在各种预测任务中表现良好。[ReLU提供了一种非常简单的非线性变换]。给定元素,ReLU函数被定义为该元素与的最大值:

ReLU函数通过将相应的活性值设为0,仅保留正元素并丢弃所有负元素。

当输入为负时,ReLU函数的导数为0,而当输入为正时,ReLU函数的导数为1。 当输入值精确等于0时,ReLU函数不可导。 在此时,默认使用左侧的导数,即当输入为0时导数为0。

使用ReLU的原因是,它求导表现得特别好:要么让参数消失,要么让参数通过。这使得优化表现得更好,并且ReLU减轻了困扰以往神经网络的梯度消失问题。

ReLU函数有许多变体,包括参数化ReLU(Parameterized ReLU,pReLU)该变体为ReLU添加了一个线性项,因此即使参数是负的,某些信息仍然可以通过:

  • 优点
    • 计算简单,收敛速度快。
    • 有效缓解梯度消失问题。
  • 缺点
    • 梯度为0的死区(如果输入为负,则梯度为0,导致神经元“死亡”)。

1.2 sigmoid函数

对于一个定义域在中的输入,sigmoid函数将输入变换为区间(0, 1)上的输出。因此,sigmoid通常称为挤压函数(squashing function):它将范围(-inf, inf)中的任意输入压缩到区间(0, 1)中的某个值:

sigmoid函数是一个平滑的、可微的阈值单元近似。当想要将输出视作二元分类问题的概率时,sigmoid仍然被广泛用作输出单元上的激活函数(sigmoid可以视为softmax的特例)。然而,sigmoid在隐藏层中已经较少使用,它在大部分时候被更简单、更容易训练的ReLU所取代。当输入接近0时,sigmoid函数接近线性变换。

sigmoid函数的导数为下面的公式:

sigmoid函数以及导数图像如下所示。

当输入为0时,sigmoid函数的导数达到最大值0.25;而输入在任一方向上越远离0点时,导数越接近0。

  • 优点
    • 将输入值映射到 (0, 1) 区间,适合用于输出概率。
  • 缺点
    • 梯度消失问题(梯度在极端值时非常小,导致训练速度变慢)。
    • 输出不以0为中心(可能导致收敛速度慢)。

1.3 tanh函数

与sigmoid函数类似,tanh(双曲正切)函数也能将其输入压缩转换到区间(-1, 1)上。tanh函数的公式如下:

当输入在0附近时,tanh函数接近线性变换。函数的形状类似于sigmoid函数,不同的是tanh函数关于坐标系原点中心对称。

tanh函数的导数是:

tanh函数以及导数图像如下所示。

当输入接近0时,tanh函数的导数接近最大值1。与sigmoid函数图像类似,输入在任一方向上越远离0点,导数越接近0。

  • 优点
    • 输出以0为中心,比Sigmoid更适合用于隐藏层。
  • 缺点
    • 仍然存在梯度消失问题。

1.4 Softmax函数

Softmax函数是用于多类分类问题的激活函数,在多类分类问题中,超过两个类标签则需要类成员关系。对于长度为的任意实向量,Softmax函数可以将其压缩为长度为,值在范围内,并且向量中元素的总和为1的实向量。

Softmax函数与正常的max函数不同:max函数仅输出最大值,但Softmax函数确保较小的值具有较小的概率,并且不会直接丢弃。Softmax函数的分母结合了原始输出值的所有因子,这意味着Softmax函数获得的各种概率彼此相关。

Softmax函数以及导数图像如下所示。

  • 优点
    • 将输入值映射为概率分布,适合多分类任务的输出层。
  • 缺点
    • 不适合作为隐藏层的激活函数。

1.5 Swish函数

Swish 的设计受到了 LSTM 和高速网络中gating的sigmoid函数使用的启发。使用相同的gating值来简化gating机制,这称为self-gating。

self-gating的优点在于它只需要简单的标量输入,而普通的gating则需要多个标量输入。这使得诸如Swish之类的self-gated激活函数能够轻松替换以单个标量为输入的激活函数(如:ReLU),而无需更改隐藏容量或参数数量。

Swish函数以及导数图像如下所示。

  • 输出范围:负无穷到正无穷
  • 优点
    • 在许多任务中表现优于ReLU。
    • 具有平滑的非线性特性。
  • 缺点
    • 计算复杂度比ReLU高。

1.6 Exponential Linear Unit(ELU)

ELU 的提出也解决了ReLU 的问题。与ReLU相比,ELU有负值,这会使激活的平均值接近零。均值激活接近于零可以使学习更快,因为它们使梯度更接近自然梯度。

  • 优点
    • 缓解梯度消失问题。
    • 输出均值接近0,有助于加快学习。
  • 缺点
    • 计算量比ReLU稍大。

1.7 GAUSSIAN ERROR LINEAR UNIT(GELU)

GELU 是在这篇论文中提出的,它定义函数为:

其中 是一个输入值, 是一个零均值和单位方差的高斯随机变量,用于模拟输入, 是输入小于或等于给定值的概率。

近似计算公式

计算 GELU 对输入的导数:

其中 处概率密度函数的值。

GELU 可以使用高斯误差函数计算

是Gauss Error Function

1
2
3
4
5
#Using PyTorch
import torch
def gelu(x):
cdf = 0.5 * (1.0 + torch.erf(x / np.sqrt(2.0)))
return x * cdf

GELU、ReLU、ELU对比

GELU的优点

GELU的优点是,它在处理负数时不会像ReLU一样将输入裁剪到0,这可能导致梯度消失的问题。

  • 具有更光滑的导数:
    • GELU函数的导数是连续的,这使得在训练深度神经网络时可以更容易地传播梯度,避免了ReLU函数在 处的导数不连续的问题,从而减少了训练过程中出现的梯度消失问题
  • 可以加速收敛:
    • GELU函数在激活函数的非线性变换中引入了类似于sigmoid函数的变换,这使得GELU函数的输出可以落在一个更广的范围内,有助于加速模型的收敛速度。

1.7.1 GELU详解

ReLU 激活对于正输入是恒等映射,对于其他输入是零映射(零或恒等映射)。现在,描述一个可以导出 GELU的随机零或恒等映射。假设输入 如下:

其中 是批量大小, 是输入特征的数量。本质上是假设每个输入特征都是正态分布的随机变量,均值为零,标准差为一。 这可以使用分布的概率密度函数 (pdf) 进行可视化,如下所示:

现在想要以随机(随机)的方式对 应用零或恒等映射,类似于 ReLU,但希望较大的 值有更高的概率被保留。可以通过定义以下内容来实现这一点:

上述公式代表特定的输入值 保留的概率等于任何输入 小于或等于它的概率。对于离散概率分布,这可以通过简单地累加所有小于或等于 的值的概率来计算。然而,对于像高斯分布这样的连续分布,使用积分来计算这个函数:

其中 被称为累积分布函数(cdf),如下所示的图中所示:

等于概率密度函数曲线左侧 下的面积。这里是不同 值的可视化:

计算

高斯误差函数(erf)是在概率、统计和偏微分方程中出现的一个特殊函数。erf 定义为

使用 erf 来计算 。下面,使用代数运算以 的形式表达

,可以重写 erf 为:

通过改变积分的极限来将这个积分分成两部分,像这样:

代入 方程:

由上面可视化 的图,以曲线下的面积表示。 是一半。

想要以 的形式的 ,可以通过设 来做到这一点:

创建一个确定性函数

上述定义了一个随机正则器,它以 的概率对输入 应用零或恒等(SOI)映射。现在使用这个来创建一个用作激活的确定性函数。注意,SOI 可以做两件事之一:以 的概率应用恒等映射,或以 的概率应用零映射。这对应于一个伯努利试验。这个试验的期望值(均值)是:

这正是 GELU 激活函数。

计算导数

其中 处概率密度函数的值。

1.8 总结

基于ReLU的激活函数(包括ReLU本身),它们在几乎所有任务中都经过了实证,证明非常有效。之后,尝试为隐藏层选择其他激活函数,可能是多层的不同激活函数,以观察性能的变化。

神经网络架构、机器学习任务等都会影响激活函数的选择。例如,如果任务是二元分类,则sigmoid激活函数是一个很好的选择,但对于多类分类,softmax函数更好,因为它将输出每个类别的概率表示。

在卷积神经网络中,可以使用基于ReLU的激活函数来提高收敛速度。然而,一些架构需要特定的激活函数。例如,循环神经网络架构和长短期记忆网络架构使用sigmoid函数和tanh函数,它们的逻辑门式架构如果使用ReLU则无法工作。

实际应用中,可以通过实验和调参来确定最适合的激活函数。

1.9 pytorch实现MLP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import torch
from torch import nn
from d2l import torch as d2l

net = nn.Sequential(nn.Flatten(),
nn.Linear(784, 256),
nn.ReLU(),
nn.Linear(256, 10))

def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights);

batch_size, lr, num_epochs = 256, 0.1, 10
loss = nn.CrossEntropyLoss(reduction='none')
trainer = torch.optim.SGD(net.parameters(), lr=lr)

train_iter, test_iter = load_data_fashion_mnist(batch_size)
train(net, train_iter, test_iter, loss, num_epochs, trainer)

二、欠拟合和过拟合

训练误差和验证误差都很严重, 但它们之间仅有一点差距。 如果模型不能降低训练误差,这可能意味着模型过于简单(即表达能力不足), 无法捕获试图学习的模式。 此外,由于训练和验证误差之间的泛化误差很小, 有理由相信可以用一个更复杂的模型降低训练误差。 这种现象被称为欠拟合(underfitting)。训练误差明显低于验证误差时要小心, 这表明严重的过拟合(overfitting)。

  • 在跨层连接上,不同于ResNet中将输入与输出相加,稠密连接网络(DenseNet)在通道维上连结输入与输出。
  • DenseNet的主要构建模块是稠密块和过渡层。
  • 在构建DenseNet时,我们需要通过添加过渡层来控制网络的维数,从而再次减少通道的数量。

线性代数中最有用的一些运算符是范数(norm)。非正式地说,向量的范数是表示一个向量有多大。这里考虑的大小(size)概念不涉及维度,而是分量的大小。

在线性代数中,向量范数是将向量映射到标量的函数。给定任意向量,向量范数要满足一些属性。第一个性质是:如果我们按常数因子缩放向量的所有元素,其范数也会按相同常数因子的绝对值缩放:

第二个性质是熟悉的三角不等式:

第三个性质简单地说范数必须是非负的:

这是有道理的。因为在大多数情况下,任何东西的最小的大小是0。最后一个性质要求范数最小为0,当且仅当向量全由0组成。

范数听起来很像距离的度量。欧几里得距离和毕达哥拉斯定理中的非负性概念和三角不等式可能会给出一些启发。事实上,欧几里得距离是一个范数:假设维向量中的元素是,其 [范数 是向量元素平方和的平方根:]

其中,在范数中常常省略下标,也就是说等同于
在代码中,我们可以按如下方式计算向量的范数。

1
2
u = torch.tensor([3.0, -4.0])
torch.norm(u)

深度学习中更经常地使用范数的平方,也会经常遇到[范数,它表示为向量元素的绝对值之和:]

范数相比,范数受异常值的影响较小。为了计算范数,我们将绝对值函数和按元素求和组合起来。

范数和范数都是更一般的范数的特例:

类似于向量的范数,[矩阵](Frobenius范数(Frobenius norm)是矩阵元素平方和的平方根:)

Frobenius范数满足向量范数的所有性质,它就像是矩阵形向量的范数。调用以下函数将计算矩阵的Frobenius范数。

1
torch.norm(torch.ones((4, 9)))

2.2 权重衰减

在训练参数化机器学习模型时,权重衰减(weight decay)是最广泛使用的正则化的技术之一,它通常也被称为正则化。正则化是处理过拟合的常用方法,在训练集的损失函数中加入惩罚项,以降低学习到的模型的复杂度。保持模型简单的一个特别的选择是使用惩罚的权重衰减。这会导致学习算法更新步骤中的权重衰减。

通过线性函数中的权重向量的某个范数来度量其复杂性,例如。要保证权重向量比较小,最常用方法是将其范数作为惩罚项加到最小化损失的问题中。将原来的训练目标最小化训练标签上的预测损失,调整为最小化预测损失和惩罚项之和

损失:

加入正则化的损失:

除以,当取一个二次函数的导数时,会抵消,以确保更新表达式看起来既漂亮又简单。通过平方范数,去掉平方根,留下权重向量每个分量的平方和。这使得惩罚的导数很容易计算:导数的和等于和的导数。

为什么首先使用范数,而不是范数。事实上,这个选择在整个统计领域中都是有效的和受欢迎的。正则化线性模型构成经典的岭回归(ridge regression)算法,正则化线性回归是统计学中类似的基本模型,通常被称为套索回归(lasso regression)。使用范数的一个原因是它对权重向量的大分量施加了巨大的惩罚。这使得学习算法偏向于在大量特征上均匀分布权重的模型。在实践中,这可能使它们对单个变量中的观测误差更为稳定。相比之下,惩罚会导致模型将权重集中在一小部分特征上,而将其他权重清除为零。这称为特征选择(feature selection),这可能是其他场景下需要的。

正则化回归的小批量随机梯度下降更新如下式:

根据估计值与观测值之间的差异来更新。然而,同时也在试图将的大小缩小到零。这就是为什么这种方法有时被称为权重衰减。仅考虑惩罚项,优化算法在训练的每一步衰减权重。与特征选择相比,权重衰减提供了一种连续的机制来调整函数的复杂度。较小的值对应较少约束的,而较大的值对的约束更大。

2.3 pytorch代码示例

用如下公式生成数据:

1
2
3
4
5
6
7
8
9
10
11
%matplotlib inline
import torch
from torch import nn
from d2l import torch as d2l

n_train, n_test, num_inputs, batch_size = 20, 100, 200, 5
true_w, true_b = torch.ones((num_inputs, 1)) * 0.01, 0.05
train_data = d2l.synthetic_data(true_w, true_b, n_train)
train_iter = d2l.load_array(train_data, batch_size)
test_data = d2l.synthetic_data(true_w, true_b, n_test)
test_iter = d2l.load_array(test_data, batch_size, is_train=False)

定义训练过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def train_concise(wd):
net = nn.Sequential(nn.Linear(num_inputs, 1))
for param in net.parameters():
param.data.normal_()
loss = nn.MSELoss(reduction='none')
num_epochs, lr = 100, 0.003
# 偏置参数没有衰减
trainer = torch.optim.SGD([
{"params":net[0].weight,'weight_decay': wd},
{"params":net[0].bias}], lr=lr)
animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
xlim=[5, num_epochs], legend=['train', 'test'])
for epoch in range(num_epochs):
for X, y in train_iter:
trainer.zero_grad()
l = loss(net(X), y)
l.mean().backward()
trainer.step()
if (epoch + 1) % 5 == 0:
animator.add(epoch + 1,
(d2l.evaluate_loss(net, train_iter, loss),
d2l.evaluate_loss(net, test_iter, loss)))
print('w的L2范数:', net[0].weight.norm().item())

忽略正则化

1
train_concise(0)

使用权重衰减

1
train_concise(3)

三、Dropout

在训练过程中,在计算后续层之前向网络的每一层注入噪声。因为当训练一个有多层的深层网络时,注入噪声只会在输入-输出映射上增强平滑性。这个想法被称为暂退法(dropout)。暂退法在前向传播过程中,计算每一内部层的同时注入噪声,这已经成为训练神经网络的常用技术。这种方法之所以被称为暂退法,因为从表面上看是在训练过程中丢弃(drop out)一些神经元。在整个训练过程的每一次迭代中,标准暂退法包括在计算下一层之前将当前层中的一些节点置零。

dropout前后的多层感知机

将Dropout应用到隐藏层,以的概率将隐藏单元置为零时,结果可以看作一个只包含原始神经元子集的网络。比如在上图中,删除了,因此输出的计算不再依赖于,并且它们各自的梯度在执行反向传播时也会消失。这样,输出层的计算不能过度依赖于的任何一个元素。

3.1 代码示例

加载数据

1
2
3
4
5
6
7
8
9
import torch
from torch import nn
from d2l import torch as d2l

num_epochs, lr, batch_size = 10, 0.5, 256
dropout1, dropout2 = 0.2, 0.5
loss = nn.CrossEntropyLoss(reduction='none')
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
trainer = torch.optim.SGD(net.parameters(), lr=lr)

定义模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
net = nn.Sequential(nn.Flatten(),
nn.Linear(784, 256),
nn.ReLU(),
# 在第一个全连接层之后添加一个dropout层
nn.Dropout(dropout1),
nn.Linear(256, 256),
nn.ReLU(),
# 在第二个全连接层之后添加一个dropout层
nn.Dropout(dropout2),
nn.Linear(256, 10))

def init_weights(m):
if type(m) == nn.Linear:
nn.init.normal_(m.weight, std=0.01)

net.apply(init_weights);

训练

1
train1(net, train_iter, test_iter, loss, num_epochs, trainer)

Dropout在前向传播过程中,计算每一内部层的同时丢弃一些神经元。Dropout可以避免过拟合,它通常与控制权重向量的维数和大小结合使用的。Dropout仅在训练期间使用。

四、前向传播和反向传播

4.1 前向传播

前向传播(forward propagation或forward pass)指的是:按顺序(从输入层到输出层)计算和存储神经网络中每层的结果。

为了简单起见,假设输入样本是 ,并且隐藏层不包括偏置项。这里的中间变量是:

其中是隐藏层的权重参数。将中间变量通过激活函数后,得到长度为的隐藏激活向量:

隐藏变量也是一个中间变量。假设输出层的参数只有权重,可以得到输出层变量,它是一个长度为的向量:

假设损失函数为,样本标签为,可以计算单个数据样本的损失项,

根据正则化的定义,给定超参数,正则化项为

其中矩阵的Frobenius范数是将矩阵展平为向量后应用的范数。最后,模型在给定数据样本上的正则化损失为:

称为目标函数(objective function)。

计算图有助于我们可视化计算中操作符和变量的依赖关系。下图与上述简单网络相对应的计算图,其中正方形表示变量,圆圈表示操作符。左下角表示输入,右上角表示输出。注意显示数据流的箭头方向主要是向右和向上的。

前向传播的计算图

4.2 反向传播

反向传播(backward propagation或backpropagation)指的是计算神经网络参数梯度的方法。简言之,该方法根据微积分中的链式规则,按相反的顺序从输出层到输入层遍历网络。该算法存储了计算某些参数梯度时所需的任何中间变量(偏导数)。假设函数,其中输入和输出是任意形状的张量。利用链式法则,可以计算关于的导数

在这里,使用运算符在执行必要的操作(如换位和交换输入位置)后将其参数相乘。对于向量,这很简单,它只是矩阵-矩阵乘法。对于高维张量,使用适当的对应项。运算符指代了所有的这些符号。

回想一下,在前向传播计算图中的单隐藏层简单网络的参数是。反向传播的目的是计算梯度。为此,应用链式法则,依次计算每个中间变量和参数的梯度。计算的顺序与前向传播中执行的顺序相反,因为我们需要从计算图的结果开始,并朝着参数的方向努力。第一步是计算目标函数相对于损失项和正则项的梯度。

接下来,根据链式法则计算目标函数关于输出层变量的梯度:

接下来,计算正则化项相对于两个参数的梯度:

现在可以计算最接近输出层的模型参数的梯度。使用链式法则得出:

为了获得关于的梯度,我们需要继续沿着输出层到隐藏层反向传播。关于隐藏层输出的梯度由下式给出:

由于激活函数是按元素计算的,计算中间变量的梯度需要使用按元素乘法运算符,用表示:

最后,可以得到最接近输入层的模型参数的梯度。根据链式法则,得到:

4.3 训练神经网络

在训练神经网络时,前向传播和反向传播相互依赖。对于前向传播,沿着依赖的方向遍历计算图并计算其路径上的所有变量。然后将这些用于反向传播,其中计算顺序与计算图的相反。

蓝色的过程叫 Forward Pass,红色的过程叫 Backward Pass,整个过程叫 Backpropagation

以上述简单网络为例:一方面,在前向传播期间计算正则项取决于模型参数的当前值。它们是由优化算法根据最近迭代的反向传播给出的。另一方面,反向传播期间参数的梯度计算,取决于由前向传播给出的隐藏变量的当前值。

因此,在训练神经网络时,在初始化模型参数后,交替使用前向传播和反向传播,利用反向传播给出的梯度来更新模型参数。反向传播重复利用前向传播中存储的中间值,以避免重复计算。带来的影响之一是需要保留中间值,直到反向传播完成。这也是训练比单纯的预测需要更多的内存(显存)的原因之一。此外,这些中间值的大小与网络层的数量和批量的大小大致成正比。因此,使用更大的批量来训练更深层次的网络更容易导致内存不足(out of memory)错误。

五、梯度消失和梯度爆炸

考虑一个具有层、输入和输出的深层网络。每一层由变换定义,该变换的参数为权重,其隐藏变量是(令 )。
网络可以表示为:

如果所有隐藏变量和输入都是向量,可以将关于任何一组参数的梯度写为下式:

换言之,该梯度是个矩阵与梯度向量 的乘积。因此,容易受到数值下溢问题的影响.当将太多的概率乘在一起时,这些问题经常会出现。在处理概率时,一个常见的技巧是切换到对数空间,即将数值表示的压力从尾数转移到指数。不幸的是,上面的问题更为严重:最初,矩阵 可能具有各种各样的特征值。他们可能很小,也可能很大;他们的乘积可能非常大,也可能非常小。

不稳定梯度带来的风险不止在于数值表示;不稳定梯度也威胁到优化算法的稳定性。可能面临一些问题。要么是梯度爆炸(gradient exploding)问题:参数更新过大,破坏了模型的稳定收敛;要么是梯度消失(gradient vanishing)问题:参数更新过小,在每次更新时几乎不会移动,导致模型无法学习。

5.1 梯度消失

sigmoid是导致梯度消失问题的一个常见的原因

正如上图,当sigmoid函数的输入很大或是很小时,它的梯度都会消失。此外,当反向传播通过许多层时,整个乘积的梯度可能会消失。当网络有很多层时,除非很小心,否则在某一层可能会切断梯度。事实上,这个问题曾经困扰着深度网络的训练。因此,更稳定的ReLU系列函数已经成为从业者的默认选择。

5.2 梯度爆炸

相反,梯度爆炸可能同样令人烦恼。为了更好地说明这一点,生成100个高斯随机矩阵,并将它们与某个初始矩阵相乘。对于选择的尺度(方差),矩阵乘积发生爆炸。当这种情况是由于深度网络的初始化所导致时,没有机会让梯度下降优化器收敛。

1
2
3
4
5
6
7
import torch
M = torch.normal(0, 1, size=(4,4))
print('一个矩阵 \n',M)
for i in range(100):
M = torch.mm(M,torch.normal(0, 1, size=(4, 4)))

print('乘以100个矩阵后\n', M)
1
2
3
4
5
6
7
8
9
10
一个矩阵 
tensor([[-0.4430, 1.8467, 1.2274, 0.2537],
[ 1.6749, -1.5996, 0.6402, 0.1141],
[-0.1859, -0.4506, 2.5819, -1.3329],
[ 2.7346, 0.1642, -0.6078, -0.0507]])
乘以100个矩阵后
tensor([[ 6.9875e+23, 5.5570e+23, 7.6843e+23, -1.9781e+23],
[-6.3054e+23, -5.0146e+23, -6.9342e+23, 1.7850e+23],
[ 6.4354e+23, 5.1180e+23, 7.0772e+23, -1.8218e+23],
[-1.1732e+24, -9.3301e+23, -1.2902e+24, 3.3212e+23]])

解决(或至少减轻)上述问题的一种方法是进行参数初始化,优化期间的注意和适当的正则化也可以进一步提高稳定性。框架默认使用随机初始化方法,对于中等难度的问题,这种方法通常很有效。Xavier初始化方法在实践中被证明是有效的。

六、前馈神经网络(Feedforward Neural Network, FNN)

多层感知器(MLP, Multi-Layer Perceptron)和前馈神经网络(Feedforward Neural Network, FNN)是深度学习中两个经常被使用的术语,它们经常被互换使用。

多层感知器 (MLP):

MLP 是一个由三种类型的层组成的神经网络:输入层、一个或多个隐藏层和输出层。
每一层都由多个神经元组成,这些神经元与前一层的所有神经元全连接。
MLP 使用非线性激活函数,例如 sigmoid、tanh 或 ReLU,否则多个线性层的组合仍然会是线性的。
MLP 主要用于结构化数据的分类和回归任务。

前馈神经网络 (FNN):

FNN 是一种更为泛化的术语,用于描述数据在网络中单向传播的网络,从输入层到输出层,没有反馈或循环。
MLP 实际上是FNN的一个特例。这意味着所有的 MLP 都是 FNN,但并不是所有的 FNN 都是 MLP。例如,有些前馈神经网络可能包括卷积层或其他特殊类型的层。
FNN的主要特点是它们没有循环或记忆元素,因此与循环神经网络(RNN)和其他包含反馈机制的网络不同。

总结一下,MLP 和 FNN 在许多上下文中可以互换使用,尤其是当我们谈论只有全连接层的网络时。但技术上,MLP 是 FNN 的一个子集,因为FFNN可以包括除全连接层之外的其他类型的层。

参考

  1. GELU激活函数详解
  2. Activation functions in neural networks
  3. On the GELU Activation Function
  4. 李沐-动手学深度学习第二版
  5. 前馈神经网络和多层感知机

神经网络(二)——多层感知机(Multilayer Perceptron)
https://mztchaoqun.com.cn/posts/D55_MLP/
作者
mztchaoqun
发布于
2024年11月24日
许可协议