PyTorch torch.nn.Dropout 函数
torch.nn.Dropout 是 PyTorch 中用于正则化的模块。
它通过随机将输入元素的置零来减少神经元之间的协同适应,从而防止过拟合。
函数定义
torch.nn.Dropout(p=0.5, inplace=False)
参数说明:
p(float): 每个元素被置零的概率。默认为 0.5。inplace(bool): 是否原地执行操作。默认为 False。
使用示例
示例 1: 基本用法
创建并使用 Dropout 层:
实例
import torch
import torch.nn as nn
# 创建 Dropout 层,丢弃概率 0.5
dropout = nn.Dropout(p=0.5)
# 训练模式(Dropout 生效)
dropout.train()
# 创建输入
input_tensor = torch.ones(1, 10)
print("输入:", input_tensor.squeeze().tolist())
# 前向传播多次,观察随机性
for i in range(3):
output = dropout(input_tensor)
print(f"第{i+1}次输出:", output.squeeze().tolist())
import torch.nn as nn
# 创建 Dropout 层,丢弃概率 0.5
dropout = nn.Dropout(p=0.5)
# 训练模式(Dropout 生效)
dropout.train()
# 创建输入
input_tensor = torch.ones(1, 10)
print("输入:", input_tensor.squeeze().tolist())
# 前向传播多次,观察随机性
for i in range(3):
output = dropout(input_tensor)
print(f"第{i+1}次输出:", output.squeeze().tolist())
可以看到,每次调用时随机约一半的元素被置零。
示例 2: 训练 vs 评估模式
Dropout 在训练和评估时的行为不同:
实例
import torch
import torch.nn as nn
dropout = nn.Dropout(p=0.5)
# 训练模式
dropout.train()
train_output = dropout(torch.ones(4, 10))
print("训练模式 - 激活比例:", (train_output != 0).float().mean().item())
# 评估模式
dropout.eval()
eval_output = dropout(torch.ones(4, 10))
print("评估模式 - 激活比例:", (eval_output != 0).float().mean().item())
print("评估模式输出:", eval_output[0].tolist())
import torch.nn as nn
dropout = nn.Dropout(p=0.5)
# 训练模式
dropout.train()
train_output = dropout(torch.ones(4, 10))
print("训练模式 - 激活比例:", (train_output != 0).float().mean().item())
# 评估模式
dropout.eval()
eval_output = dropout(torch.ones(4, 10))
print("评估模式 - 激活比例:", (eval_output != 0).float().mean().item())
print("评估模式输出:", eval_output[0].tolist())
评估时 Dropout 不起作用,输出保持不变。
示例 3: 在神经网络中使用
典型的带 Dropout 的全连接网络:
实例
import torch
import torch.nn as nn
class DropoutNet(nn.Module):
def __init__(self, input_dim=784, hidden_dim=256, output_dim=10, dropout_rate=0.5):
super(DropoutNet, self).__init__()
self.fc1 = nn.Linear(input_dim, hidden_dim)
self.dropout1 = nn.Dropout(p=dropout_rate)
self.fc2 = nn.Linear(hidden_dim, hidden_dim)
self.dropout2 = nn.Dropout(p=dropout_rate)
self.fc3 = nn.Linear(hidden_dim, output_dim)
self.relu = nn.ReLU()
def forward(self, x):
x = self.relu(self.fc1(x))
x = self.dropout1(x) # 第一次 Dropout
x = self.relu(self.fc2(x))
x = self.dropout2(x) # 第二次 Dropout
x = self.fc3(x)
return x
model = DropoutNet()
# 训练模式
model.train()
input_data = torch.randn(32, 784)
output = model(input_data)
print("训练模式输出形状:", output.shape)
# 评估模式
model.eval()
output = model(input_data)
print("评估模式输出形状:", output.shape)
import torch.nn as nn
class DropoutNet(nn.Module):
def __init__(self, input_dim=784, hidden_dim=256, output_dim=10, dropout_rate=0.5):
super(DropoutNet, self).__init__()
self.fc1 = nn.Linear(input_dim, hidden_dim)
self.dropout1 = nn.Dropout(p=dropout_rate)
self.fc2 = nn.Linear(hidden_dim, hidden_dim)
self.dropout2 = nn.Dropout(p=dropout_rate)
self.fc3 = nn.Linear(hidden_dim, output_dim)
self.relu = nn.ReLU()
def forward(self, x):
x = self.relu(self.fc1(x))
x = self.dropout1(x) # 第一次 Dropout
x = self.relu(self.fc2(x))
x = self.dropout2(x) # 第二次 Dropout
x = self.fc3(x)
return x
model = DropoutNet()
# 训练模式
model.train()
input_data = torch.randn(32, 784)
output = model(input_data)
print("训练模式输出形状:", output.shape)
# 评估模式
model.eval()
output = model(input_data)
print("评估模式输出形状:", output.shape)
示例 4: 在 CNN 中使用 Dropout2d
nn.Dropout2d 按通道丢弃整个特征图:
实例
import torch
import torch.nn as nn
# Dropout2d 按通道丢弃
dropout2d = nn.Dropout2d(p=0.5)
# 输入:batch=1,通道=4,高=4,宽=4
input_tensor = torch.ones(1, 4, 4, 4)
dropout2d.train()
output = dropout2d(input_tensor)
print("Dropout2d 输出形状:", output.shape)
print("非零通道数:", (output.sum(dim=(2, 3)) != 0).sum().item())
import torch.nn as nn
# Dropout2d 按通道丢弃
dropout2d = nn.Dropout2d(p=0.5)
# 输入:batch=1,通道=4,高=4,宽=4
input_tensor = torch.ones(1, 4, 4, 4)
dropout2d.train()
output = dropout2d(input_tensor)
print("Dropout2d 输出形状:", output.shape)
print("非零通道数:", (output.sum(dim=(2, 3)) != 0).sum().item())
示例 5: 不同丢弃率的效果
丢弃率对网络的影响:
实例
import torch
import torch.nn as nn
for p in [0.1, 0.3, 0.5, 0.7]:
dropout = nn.Dropout(p=p)
dropout.train()
# 多次运行取平均
total_active = 0
for _ in range(100):
output = dropout(torch.ones(1000))
total_active += (output != 0).float().sum().item()
avg_active = total_active / 100 / 1000
print(f"p={p} - 平均激活比例: {avg_active:.2%} (期望: {1-p:.2%})")
import torch.nn as nn
for p in [0.1, 0.3, 0.5, 0.7]:
dropout = nn.Dropout(p=p)
dropout.train()
# 多次运行取平均
total_active = 0
for _ in range(100):
output = dropout(torch.ones(1000))
total_active += (output != 0).float().sum().item()
avg_active = total_active / 100 / 1000
print(f"p={p} - 平均激活比例: {avg_active:.2%} (期望: {1-p:.2%})")
Dropout 类型对比
| 类型 | 丢弃方式 | 适用场景 |
|---|---|---|
nn.Dropout |
随机置零单个元素 | 全连接层、特征向量 |
nn.Dropout2d |
随机置零整个通道 | 卷积层特征图 |
nn.Dropout3d |
随机置零整个三维通道 | 3D 卷积特征 |
常见问题
Q1: Dropout 丢弃率如何选择?
- 0.1-0.3: 较轻的正则化,适合大数据集
- 0.4-0.5: 常用的默认值
- 0.5+: 较强的正则化,适合小数据集
Q2: Dropout 放在哪里?
通常放在全连接层之后、激活函数之后。也可放在激活函数之前。
Q3: 评估时需要关闭 Dropout 吗?
是的,评估时使用 model.eval() 自动关闭 Dropout。
使用场景
nn.Dropout 主要应用场景包括:
- 防止过拟合: 减少神经元之间的依赖
- 模型集成: 近似多个网络的效果
- 全连接层: 最常用于 FC 层
- 特征丢弃: 提高模型的鲁棒性
注意:Dropout 在训练时开启,评估时一定要切换到 eval 模式,否则输出会不稳定。

PyTorch torch.nn 参考手册