动手学深度学习(pytorch)学习记录16-暂退法[学习记录]

暂退法

暂退法(Dropout)是深度学习中一种常用的正则化技术,由 Geoffrey Hinton 和他的同事们在 2012 年提出。它主要用于防止神经网络模型过拟合,提高模型的泛化能力。暂退法是一种简单而有效的正则化方法,被广泛应用于各种深度学习模型中,尤其是在图像和语音识别等领域。

暂退法的工作原理:

随机丢弃:在训练过程中,暂退法会在每次迭代时随机丢弃(即将输出设置为零)网络中的一部分神经元。丢弃的神经元在当前迭代中不会参与前向和反向传播。

保留概率:每个神经元被丢弃的概率是预先设定的,通常由超参数控制。例如,如果设置为 0.5,则每个神经元有 50% 的概率在每次迭代中被丢弃。

训练和测试差异:在训练过程中使用暂退法时,神经元的丢弃是随机的,而在测试或实际使用模型时,所有神经元都参与计算,但输出需要通过保留概率进行缩放,以保持输出的期望值不变。

暂退法的优点:

减少过拟合:通过随机丢弃神经元,暂退法迫使网络学习更加鲁棒的特征,而不是依赖于特定的神经元集合。

模型平均:暂退法可以看作是一种模型平均技术,因为它在训练过程中隐式地训练了多个不同的“稀疏”网络。这些网络的预测结果在测试时被平均,这通常比单个网络的预测更稳定。

防止共适应:暂退法通过随机丢弃神经元,防止了神经元之间形成过于紧密的依赖关系,即共适应(co-adaptation)。

暂退法的缺点:

计算效率:由于在训练过程中需要多次前向和反向传播,暂退法可能会增加训练时间。

超参数选择:合适的丢弃概率需要通过实验来确定,这可能会增加模型调优的工作量。

可能的副作用:在某些情况下,暂退法可能会引入额外的噪声,影响模型的学习效率。
暂退法是一种简单而有效的正则化方法,被广泛应用于各种深度学习模型中,尤其是在图像和语音识别等领域。

代码实例

import torch
from torch import nn
from d2l import torch as d2l

实现 dropout_layer 函数, 该函数以dropout的概率丢弃张量输入X中的元素, 将剩余部分除以1.0-dropout

def dropout_layer(X, dropout):
    assert 0 <= dropout <= 1 # 使用 assert 语句确保 dropout 参数的值在 0 到 1 之间
    # 在本情况中,所有元素都被丢弃
    if dropout == 1:
        return torch.zeros_like(X)
    # 在本情况中,所有元素都被保留
    if dropout == 0:
        return X
    mask = (torch.rand(X.shape) > dropout).float()
    return mask * X / (1.0 - dropout)

解释一下mask那段代码:
创建一个与 X 形状相同的随机张量 mask,其中的元素是从均匀分布 [0, 1) 中随机抽取的。
将 mask 中的每个元素与 dropout 值进行比较,如果随机值大于 dropout,则在 mask 中保留该元素(值为 1.0),否则将该元素设置为 0。这样,mask 张量中大约有 dropout 比例的元素为 0,其余为 1。
将 mask 张量与输入 X 相乘,这样 X 中对应于 mask 中为 0 的元素将被丢弃(设置为 0)。
最后,为了保持输出张量的期望值不变,将丢弃操作后的张量除以 (1.0 - dropout)。这是因为在丢弃了一部分元素后,剩余元素的总和会减少,通过除以 (1.0 - dropout) 可以使得输出张量的期望值与原始输入 X 的期望值保持一致。

通过下面几个例子来测试dropout_layer函数,将输入X通过暂退法操作,暂退概率分别为0、0.5和1。

X= torch.arange(16, dtype = torch.float32).reshape((2, 8))
print(X, X.sum())
print(dropout_layer(X, 0.), dropout_layer(X, 0.).sum())
print(dropout_layer(X, 0.5), dropout_layer(X, 0.5).sum())
print(dropout_layer(X, 1.), dropout_layer(X, 1.).sum())

在这里插入图片描述

使用学习记录9-图像分类数据集中引入的Fashion-MNIST数据集。
定义具有两个隐藏层的多层感知机,每个隐藏层包含256个单元。

num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256

定义模型

可以将暂退法应用于每个隐藏层的输出(在激活函数之后), 并且可以为每一层分别设置暂退概率: 常见的技巧是在靠近输入层的地方设置较低的暂退概率。 下面的模型将第一个和第二个隐藏层的暂退概率分别设置为0.2和0.5, 并且暂退法只在训练期间有效。

dropout1, dropout2 = 0.2, 0.5

class Net(nn.Module):
    def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2,
                 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()

    def forward(self, X):
        H1 = self.relu(self.lin1(X.reshape((-1, self.num_inputs))))
        # 只有在训练模型时才使用dropout
        if self.training == True:
            # 在第一个全连接层之后添加一个dropout层
            H1 = dropout_layer(H1, dropout1)
        H2 = self.relu(self.lin2(H1))
        if self.training == True:
            # 在第二个全连接层之后添加一个dropout层
            H2 = dropout_layer(H2, dropout2)
        out = self.lin3(H2)
        return out


net = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2)

训练和测试

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)

在这里插入图片描述

模型简洁实现

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

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);

nn.init.normal_(m.weight, std=0.01):如果模块是 nn.Linear 层,这行代码会使用均值为 0,标准差为 0.01 的正态分布来初始化该层的权重。权重的初始化对于模型的训练和性能至关重要。
net.apply(init_weights);:这行代码调用 apply 方法,将 init_weights 函数应用于模型中的每个模块。这意味着 init_weights 函数将被用来初始化模型中所有 nn.Linear 层的权重。

trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

在这里插入图片描述

封面图片来源

欢迎点击我的主页查看更多文章。
本人学习地址https://zh-v2.d2l.ai/
恳请大佬批评指正。

  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

walfar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值