【深度学习】03-神经网络 4-1 Dropout 正则化 - 神经网络缓解过拟合的正则化方法

参数更新,只是更新一部分,剩下的部分,是进行缩放。即分数会扩大。

Dropout 正则化 是一种深度学习中常用的正则化技术,最早由 Geoffrey Hinton 等人在 2012 年提出,旨在防止神经网络的过拟合。

1. 来源

Dropout 是由 Hinton 和他的团队在论文《Improving neural networks by preventing co-adaptation of feature detectors》中首次提出。该技术的灵感来自于生物学中神经元随机失活的现象,用于模拟随机神经元的失效,增强网络的鲁棒性。

2. 作用

Dropout 的核心思想是在每次训练过程中,随机"丢弃"一部分神经元(即将这些神经元的输出设为 0),使得模型不能过度依赖某些特定的神经元。这一过程可以理解为在训练过程中构建了多个不同的子模型,然后在测试时将这些子模型的输出进行平均。

  • 防止过拟合:通过随机失活神经元,减少了神经元之间的依赖,防止模型过度拟合训练数据,提高了模型的泛化能力。

  • 提高模型鲁棒性:Dropout 迫使模型中的神经元学会独立地进行工作,因为每个神经元不能保证在每次训练中都被激活。

3. 工作机制

在训练过程中,每个神经元以一定的概率(通常为 0.5)被暂时"丢弃"。在推理(即测试)阶段,不再丢弃任何神经元,而是对所有神经元的输出进行缩放,通常是将每个神经元的输出乘以丢弃概率的补值。例如,如果训练时 50% 的神经元被丢弃,测试时就将所有神经元的输出乘以 0.5,以保持训练和测试时的期望输出一致。

4. 优势

  • 简单高效:只需在前向传播时随机丢弃神经元,且不需要额外的计算资源。

  • 提升泛化能力:在深度神经网络中,Dropout 可以显著减少过拟合,尤其是在大规模数据集不足的情况下。

总结来说,Dropout 是一种简单但有效的正则化技术,通过随机丢弃神经元来减少模型的过拟合风险,并提高其泛化性能。

代码

python 复制代码
import torch
import torch.nn as nn

def test():
    # Step 1: 初始化一个Dropout层,p=0.4表示有40%的神经元在训练时会被"丢弃"
    dropout = nn.Dropout(p=0.4)
    
    # Step 2: 创建一个随机输入张量,大小为[1, 4],表示输入层的权重,随机生成0-9之间的整数,并将其转换为float类型
    inputs = torch.randint(0, 10, size=[1, 4]).float()
    
    # Step 3: 初始化一个全连接层,输入维度为4,输出维度为5
    layer = nn.Linear(4, 5)
    
    # Step 4: 对输入数据进行前向传播,通过全连接层计算输出
    y = layer(inputs)
    
    # 打印未经过Dropout层的全连接层输出结果
    print("未失活FC层的输出结果:\n", y)
    
    # Step 5: 对全连接层的输出结果应用Dropout,随机丢弃40%的神经元
    y = dropout(y)
    
    # 打印经过Dropout层后全连接层的输出结果
    print("失活后FC层的输出结果:\n", y)

# 调用函数
test()

详细讲解:

  1. Dropout层的初始化:

    复制代码
    dropout = nn.Dropout(p=0.4)

    这里初始化了一个 Dropout 层 ,其中参数 p=0.4 表示在训练时,每个神经元有 40% 的概率会被随机"失活"(即丢弃),其输出值会被设置为 0。p 值的选择影响网络的正则化强度,p=0.4 说明这个网络比较倾向于在训练中通过随机丢弃一部分神经元来防止过拟合。

  2. 输入张量的初始化:

    复制代码
    inputs = torch.randint(0, 10, size=[1, 4]).float()

    这一行代码生成了一个大小为 [1, 4] 的张量,表示输入层的 4 个特征,张量内的值为随机生成的 0 到 9 之间的整数,并将其转换为 float 类型(因为神经网络通常需要浮点数进行运算)。

  3. 全连接层的初始化:

    复制代码
    layer = nn.Linear(4, 5)

    这里初始化了一个 线性(全连接)层,它的输入维度为 4,输出维度为 5。也就是说,这个层接收 4 个输入特征,经过权重矩阵的线性变换后输出 5 个特征。

  4. 前向传播计算输出:

    复制代码
    y = layer(inputs)

    这一行代码执行了前向传播,将输入 inputs 通过全连接层计算输出 y。这个计算过程是线性变换: y = xW + b 其中,W 是权重矩阵,b 是偏置项,x 是输入。

  5. 打印未经过 Dropout 层的输出:

    复制代码
    print("未失活FC层的输出结果:\n", y)

    在应用 Dropout 之前,打印未经过 Dropout 层的全连接层的输出结果 y。

  6. 应用 Dropout 层:

    复制代码
    y = dropout(y)

    在全连接层的输出上应用 Dropout。Dropout 通过随机丢弃 40% 的神经元(根据 p=0.4),剩下的神经元的输出会按比例缩放,以保持训练时和测试时的期望值一致。

  7. 打印经过 Dropout 层的输出:

    复制代码
    print("失活后FC层的输出结果:\n", y)

    这里打印了经过 Dropout 层之后的输出结果,可以观察到部分神经元的输出会被设置为 0。

代码运行的意义:

  1. Dropout 正则化:Dropout 是一种正则化技术,旨在防止模型过拟合。它通过在训练过程中随机丢弃一部分神经元,使得网络不会过于依赖某些特定的神经元,从而提升模型的泛化能力。

  2. 全连接层与 Dropout 的结合:通过在全连接层后应用 Dropout,可以有效减少过拟合现象,尤其是在深度神经网络的训练过程中。

这个代码演示了如何在全连接层的输出上应用 Dropout,并显示了 Dropout 失活前后的输出差异。

代码2

下面是一个用 Python 实现 Dropout 正则化 的示例代码,并附有详细注释。这个代码展示了如何在前向传播中手动实现 Dropout 正则化机制,而不是使用 PyTorch 自带的 nn.Dropout。

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

# 定义一个简单的神经网络类
class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        # 定义一个全连接层,输入4个特征,输出5个特征
        self.fc1 = nn.Linear(4, 5)

    def forward(self, x):
        # Step 1: 线性变换,输入经过全连接层
        x = self.fc1(x)

        # Step 2: 自定义Dropout实现:随机失活40%的神经元
        dropout_rate = 0.4  # 定义Dropout概率
        if self.training:  # 仅在训练模式下应用Dropout
            mask = (torch.rand(x.shape) > dropout_rate).float()  # 生成一个随机掩码
            x = x * mask / (1 - dropout_rate)  # 应用掩码并对剩下的神经元缩放
        # 如果不在训练模式(即推理模式),则不进行Dropout

        # Step 3: 使用激活函数(这里是ReLU)
        x = F.relu(x)
        return x

# 主函数
def main():
    # 创建一个神经网络实例
    model = SimpleNN()
    
    # 设置模型为训练模式(应用Dropout)
    model.train()
    
    # 创建一个随机输入张量,大小为 [1, 4],即1个样本有4个特征
    inputs = torch.randn(1, 4)

    # 打印输入
    print("输入数据:\n", inputs)

    # 前向传播
    outputs = model(inputs)
    
    # 打印输出
    print("经过Dropout后的输出:\n", outputs)

if __name__ == '__main__':
    main()

详细注释和讲解:

  1. 初始化神经网络类:

    python 复制代码
    class SimpleNN(nn.Module):
       def __init__(self):
           super(SimpleNN, self).__init__()
           # 定义一个全连接层,输入维度为4,输出维度为5
           self.fc1 = nn.Linear(4, 5)
    • 这里我们定义了一个简单的神经网络类,包含一个全连接层。nn.Linear(4, 5) 表示输入为 4 个特征,输出为 5 个特征。
  2. 前向传播与 Dropout 实现:

    python 复制代码
    def forward(self, x):
       # 线性变换,输入经过全连接层
       x = self.fc1(x)
    ​
       # 自定义Dropout实现:随机失活40%的神经元
       dropout_rate = 0.4  # 定义Dropout概率
       if self.training:  # 仅在训练模式下应用Dropout
           mask = (torch.rand(x.shape) > dropout_rate).float()  # 生成一个随机掩码
           x = x * mask / (1 - dropout_rate)  # 应用掩码并对剩下的神经元缩放
    ​
       # 使用ReLU激活函数
       x = F.relu(x)
       return x
    • 全连接层计算 :x = self.fc1(x) 对输入进行线性变换。

    • Dropout 实现:

      • 我们生成一个与输出形状相同的随机掩码 mask,该掩码中每个元素是随机生成的 0 到 1 之间的浮点数。

      • 将这些浮点数与 dropout_rate 进行比较,大于 dropout_rate 的部分保留,其他部分被设置为 0。

      • 然后,将输出乘以掩码,并对保留的神经元进行缩放(除以 1 - dropout_rate),确保期望值不变。

    • ReLU 激活:最后,使用 ReLU 激活函数对输出进行非线性处理。

  3. 主函数:

    python 复制代码
    def main():
       model = SimpleNN()
       model.train()  # 设置模型为训练模式(应用Dropout)
    ​
       inputs = torch.randn(1, 4)  # 随机生成输入数据,形状为 [1, 4]
    ​
       # 打印输入
       print("输入数据:\n", inputs)
    ​
       outputs = model(inputs)  # 前向传播
       print("经过Dropout后的输出:\n", outputs)
    • 模型训练模式 :通过 model.train() 告诉模型当前是训练模式,Dropout 将会被应用。

    • 输入数据 :随机生成大小为 [1, 4] 的输入张量,这里表示一个样本,具有 4 个特征。

    • 前向传播与输出:模型对输入进行前向传播,计算结果并打印 Dropout 后的输出。

运行结果

当你运行代码时,你会看到:

  • 输入数据是一个随机生成的 4 维向量。

  • 经过全连接层和 Dropout 操作后的输出,其中部分神经元会被丢弃,输出结果中某些值会变为 0。

总结:

  • Dropout 正则化通过随机丢弃神经元的方式防止神经网络的过拟合,尤其适合在训练深度网络时使用。

  • 在这个代码中,我们手动实现了 Dropout 的基本机制,展示了如何在前向传播中应用 Dropout,并控制训练模式和推理模式下的行为差异。

相关推荐
星马梦缘5 小时前
JetAuto VLN语义目标探索
人工智能·数码相机
好焊孙辉5 小时前
从六代螺柱焊机到AI质检:鸿栢科技的螺柱焊国产化路径
人工智能·python·科技·fpga开发
美狐美颜sdk5 小时前
直播APP开发中的视频帧处理:美颜SDK接入需要注意哪些细节?
大数据·前端·人工智能·音视频·美颜sdk
紧跟先前的步伐5 小时前
Go AI Agent 实战 12|HTTP 状态码、API 错误处理与日志
开发语言·人工智能·http·ai·golang
miofly5 小时前
Kimi K3.1 Pro 跻身智能榜第四,开源权重模型逼近头部闭源水平
人工智能
行走的小派5 小时前
Harmony输入法框架解析:IME架构、多模式输入引擎与语音识别链路
人工智能·架构·语音识别
UMI赋能企业5 小时前
AI实战交流的提问模板:从业务描述到可分析的问题
人工智能·工作流·ai应用
2601_962071005 小时前
Claude 值不值得用?价格、缓存与 API 接入成本怎么算
人工智能·缓存
自养Agent5 小时前
Agent Harness 从用到会造:prompt 不是问句,是控制面板
人工智能·大模型·llm·prompt
SeeweTek5 小时前
设计仿真先行 · 工艺精益求精 · 磁场精准输出
人工智能·亥姆霍兹线圈·磁场发生装置·seewetek·磁控机器人·传感器检测