美文网首页
深度学习-多层感知机6-暂退法(Dropout):深度神经网络的

深度学习-多层感知机6-暂退法(Dropout):深度神经网络的

作者: R7_Perfect | 来源:发表于2025-08-05 09:37 被阅读0次

在深度学习中,过拟合是一个常见的挑战,特别是当我们使用复杂模型并且训练数据相对较少时。为了避免模型在训练集上记忆过多细节、从而在新数据上表现差,研究人员提出了多种方法来正则化模型。暂退法(Dropout) 就是其中一种非常有效的正则化方法。它通过在训练过程中随机丢弃神经元的输出,迫使模型学习到更加鲁棒的特征,从而提高泛化能力。
本文将带你全面理解暂退法的原理、实现方法和实际应用,确保你能够掌握这一重要技术。

1. 重新审视过拟合

过拟合发生在模型在训练数据上表现得非常好,但在测试数据或新数据上表现较差。为了理解暂退法如何应对过拟合,我们首先回顾一下过拟合的原因。
深度神经网络由于其强大的建模能力,可以轻松地拟合训练数据中的噪声和细节,导致过拟合。例如,如果数据中的标签与特征之间没有清晰的关系,神经网络可能会“记住”这种关系,但这种关系在真实的测试数据中往往不成立。因此,即使数据量增加,模型也可能仍然会过拟合。
这就是神经网络中的偏差-方差权衡(bias-variance tradeoff)。神经网络相较于线性模型,具有更低的偏差(可以学习复杂的特征关系),但也容易产生较高的方差(对训练数据的过度适应)。为了避免这种问题,我们需要采取措施提升模型的泛化能力。

2. 扰动的稳健性

一个好的预测模型应该能够应对未知数据的变化。泛化性要求模型不仅能在训练数据上表现良好,还能在未见过的数据上做出合理预测。
暂退法正是通过在训练过程中 注入“噪声” 来提高模型的鲁棒性。具体来说,暂退法通过在每一层的前向传播过程中随机丢弃部分神经元,增加了模型对输入微小变化的适应能力,从而实现了对训练数据的正则化。

为什么要引入噪声?

噪声的引入类似于对模型进行正则化。假如一个模型非常复杂,它可能会对训练数据过度拟合,甚至学习到数据中的随机噪声。通过注入噪声,暂退法迫使神经网络避免过度依赖某些特定的特征,进而提升模型的泛化能力。

3. 暂退法的原理

暂退法的核心思想是在每一层的输出中随机选择一些神经元并将其“丢弃”(即置为零),然后再继续计算后续层的输出。这种做法可以被看作是在训练过程中形成多个不同的“子网络”,每个子网络在每次训练中都有不同的神经元组合,从而避免了过度依赖某些特定的神经元。

数学公式

假设我们在一个隐藏层中有一个神经元激活值向量 h,我们通过引入一个随机变量 r 来决定每个神经元是否被保留。对于每个神经元 hi ,其被保留的概率为 1−p,而被丢弃的概率为 p,其中 p 是暂退率。公式可以表示为:


1754293156571.png

为了使得每一层的期望输出保持不变,我们在丢弃神经元时会对剩余的神经元进行缩放。假设输入到该层的张量是 X,经过暂退法处理后,其输出为:


1754293257536.png

其中 r 是一个由均匀分布生成的随机变量,表示每个神经元是否保留。

4. 实践中的暂退法

在模型中使用暂退法

在实际应用中,我们通常会在神经网络的每一层后添加暂退法,尤其是在多层感知机(MLP)这样的深度网络中。通过设置不同的暂退率,我们可以在不同的层中控制丢弃的神经元比例,通常靠近输入层的地方会设置较低的暂退率。

示例:添加暂退法到多层感知机

假设我们有一个包含两个隐藏层的多层感知机,我们可以为每一层指定一个暂退率。以下是一个使用 PyTorch 实现的简单示例:

import torch
from torch import nn
import d2l


# 暂退法函数
def dropout_layer(X, dropout):
    assert 0 <= dropout <= 1
    if dropout == 1:
#返回一个与 X 形状相同的全零张量。
        return torch.zeros_like(X)
    if dropout == 0:
        return X
#生成一个与 X 形状相同的随机掩码,并应用于 X。
    mask = (torch.rand(X.shape) > dropout).float()
    return mask * X / (1.0 - dropout)


# 定义网络
class Net(nn.Module):
    def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2,
                 dropout1, dropout2, is_training=True):
        super(Net, self).__init__()
        self.num_inputs = num_inputs
        self.training = is_training
        self.lin1 = nn.Linear(num_inputs, num_hiddens1)
        self.lin2 = nn.Linear(num_hiddens1, num_hiddens2)
        self.lin3 = nn.Linear(num_hiddens2, num_outputs)
        self.relu = nn.ReLU()
        self.dropout1 = dropout1
        self.dropout2 = dropout2

    def forward(self, X):
        X = X.reshape((-1, self.num_inputs))  # 调整输入张量 X 的形状
        H1 = self.relu(self.lin1(X))
        # 只有在训练模型时才使用dropout
        if self.training is True:
            H1 = dropout_layer(H1, self.dropout1)
        H2 = self.relu(self.lin2(H1))
        if self.training is True:
            H2 = dropout_layer(H2, self.dropout2)
        return self.lin3(H2)


# 创建网络
net = Net(num_inputs=784, num_outputs=10, num_hiddens1=256, num_hiddens2=256, dropout1=0.2, dropout2=0.5)

代码详解:
在上述代码中,我们为两个隐藏层分别设置了不同的暂退率:第一个隐藏层为 0.2,第二个隐藏层为 0.5。
暂退法函数 dropout_layer

  • dropout_layer函数中torch.rand(X.shape) 生成一个与输入 X形状相同的张量,张量的元素是均匀分布在[0, 1)区间的随机数。然后,(torch.rand(X.shape) > dropout) 会返回一个与输入形状相同的布尔张量,表示每个元素是否大于 dropout 的值。最后,.float() 会将布尔值转换为浮点数(True 转换为 1.0,False 转换为 0.0)。这样,mask 张量的每个元素都是 0 或 1,1 表示对应的神经元被保留,0 表示对应的神经元被丢弃。
  • mask * X 计算了丢弃神经元后的输出,其中被丢弃的神经元会变成 0。为了保证期望值不变,我们将保留的神经元进行缩放,即将它们除以 (1.0 - dropout)。这是因为在 Dropout 中,丢弃了一部分神经元,相当于让剩下的神经元承担更多的权重。通过这个缩放操作,我们保证了训练时的期望输出和测试时(不进行 Dropout)的一致性。
    前向传播方法 forward
    X.reshape(-1, self.num_inputs):如果输入数据是二维(如图像数据),这里通过 reshape 把数据展平。例如,28x28 的图像就会被展平成一个 784 维的向量。
训练与测试

在训练过程中,暂退法只在训练时生效。在测试时,我们使用全连接的网络,不进行丢弃操作,从而保证网络的稳定性。

##num_epochs: 训练的轮数,这里设置为 10。
#lr: 学习率,控制参数更新的步长,这里设置为 0.5。
#batch_size: 每个批次的数据量,这里设置为 256。
num_epochs, lr, batch_size = 10, 0.5, 256
#: 使用交叉熵损失函数,适用于多分类问题。reduction='none' 表示不对损失进行求和或平均。
loss = nn.CrossEntropyLoss(reduction='none')
#: 使用 d2l 库加载 Fashion-MNIST 数据集,返回训练和测试数据迭代器。
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
#: 使用随机梯度下降(SGD)优化器,更新 net 网络的参数。
trainer = torch.optim.SGD(net.parameters(), lr=lr)
#使用 d2l 库提供的 train_ch3 函数进行模型训练和评估。
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer, batch_size)
epoch 1, train loss 0.859, train acc 0.680, test acc 0.803
epoch 2, train loss 0.516, train acc 0.813, test acc 0.827
epoch 3, train loss 0.457, train acc 0.833, test acc 0.843
epoch 4, train loss 0.419, train acc 0.846, test acc 0.851
epoch 5, train loss 0.399, train acc 0.853, test acc 0.849
epoch 6, train loss 0.380, train acc 0.861, test acc 0.829
epoch 7, train loss 0.361, train acc 0.867, test acc 0.831
epoch 8, train loss 0.352, train acc 0.869, test acc 0.855
epoch 9, train loss 0.339, train acc 0.875, test acc 0.861
epoch 10, train loss 0.334, train acc 0.877, test acc 0.853
image.png
image.png
简洁实现

对于深度学习框架的高级API,我们只需在每个全连接层之后添加一个Dropout层,将暂退概率作为唯一的参数传递给它的构造函数。在训练时,Dropout层将根据指定的暂退概率随机丢弃上一层的输出(相当于下一层的输入)。 在测试时,Dropout层仅传递数据。

dropout1 = 0.2
dropout2 = 0.5
#使用 nn.Sequential 定义了一个顺序模型。
#nn.Flatten(): 将输入展平为一维。
#nn.Linear(784, 256): 第一个全连接层,将输入特征数从 784 映射到 256。
#nn.ReLU(): 激活函数。
#nn.Dropout(dropout1): 在第一个全连接层后添加 Dropout 层,丢弃率为 dropout1。
#nn.Linear(256, 256): 第二个全连接层。
#nn.ReLU(): 激活函数。
#nn.Dropout(dropout2): 在第二个全连接层后添加 Dropout 层,丢弃率为 dropout2。
#nn.Linear(256, 10): 输出层,将特征数从 256 映射到 10(对应于 10 个类别)。
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)

#num_epochs, lr, batch_size = 10, 0.5, 256: 设置训练的超参数。
#loss = nn.CrossEntropyLoss(reduction='none'): 使用交叉熵损失函数。
#train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size): 加载 Fashion-MNIST 数据集。
#trainer = torch.optim.SGD(net.parameters(), lr=lr): 使用 SGD 优化器。
#d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer, batch_size): 使用 d2l 库的函数进行训练。
num_epochs, lr, batch_size = 10, 0.5, 256
loss = nn.CrossEntropyLoss(reduction='none')
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer, batch_size)
image.png

5. 小结

  • 暂退法是一种有效的正则化技术,通过在训练过程中丢弃部分神经元来避免模型过拟合。
  • 在训练时,暂退法帮助模型减少对特定神经元的依赖,提升模型的泛化能力。
  • 暂退法在测试时不应用,而是在训练阶段通过引入噪声来增强网络的鲁棒性。

这种方法被广泛应用于深度神经网络中,特别是在多层感知机和 卷积神经网络(CNN) 中,帮助我们构建更加高效且稳定的模型。

相关文章

  • 一文理清深度学习前馈神经网络

    ? Index 多层感知机(MLP)介绍 深度神经网络的激活函数 深度神经网络的损失函数 多层感知机的反向传播算法...

  • TensorFlow 深度学习基本概念

    1. 深度学习 特性: 多层:单层神经网络其实就是感知机(1958年由Frank Rosenblatt提出),感知...

  • 深度学习-1

    深度学习基础 介绍单层神经网络:线性回归和softmax回归多层神经网络:多层感知机 1.线性回归 例如房价预测,...

  • 反馈神经网络

    1、Reference 多层感知机MLP(机器学习5)多层感知机原理详解 & Python与R实现深度学习笔记——...

  • 感知机

    感知机 感知机算法是很多算法的鼻祖,比如支持向量机算法,神经网络与深度学习。在学习感知机的构造时可以学习到深度学习...

  • 2019-07-25 深度学习

    机器学习 - 神经网络 - 深度学习 图像 文本 语音 深度学习算法比机器学习都要好很多bp算法:多层感知器的误差...

  • 1、深度学习入门-感知机

    感知机是什么? 感知机 (perceptron):感知机是神经网络(深度学习)的起源算法,学习感知机的构造是通向神...

  • 書院中學“深度學習”項目展示活動之---英語现场作文大賽!

    深度学习的概念源于人工神经网络的研究。含多隐层的多层感知器就是一种深度学习结构。深度学习通过组合低层特征形成...

  • 人工智能 | 深度学习(人工神经网络的研究的概念)

    前言: 深度学习的概念源于人工神经网络的研究。含多隐层的多层感知器就是一种深度学习结构。深度学习通过组合低层特征形...

  • 深度学习将会改变用户体验

    深度学习的概念源于人工神经网络的研究。含多隐层的多层感知器就是一种深度学习结构。深度学习通过组合低层特征形成更加抽...

网友评论

      本文标题:深度学习-多层感知机6-暂退法(Dropout):深度神经网络的

      本文链接:https://www.haomeiwen.com/subject/vmikojtx.html