Skip to content

正则化

正则化防止模型死记硬背训练数据(过拟合),让它学到真正的规律。

训练时随机丢弃 pp 比例的神经元,强迫网络不依赖任何单个特征:

import torch.nn as nn
dropout = nn.Dropout(p=0.2)
x = torch.randn(3, 10)
output = dropout(x) # 训练时约 20% 的值变为 0
print(f"非零比例: {(output != 0).sum().item() / output.numel():.1%}")

原理:每次训练迭代,Dropout 创建了一个不同的”子网络”。推理时相当于多个子网络的集成。

p 值场景
0.1输入层,轻微正则化
0.2-0.3隐藏层,常用值
0.5过拟合严重时

在损失中加入权重的 L2 范数,鼓励权重保持较小值:

Ltotal=Loriginal+λ∑w2L_{\text{total}} = L_{\text{original}} + \lambda \sum w^2
# AdamW 的 weight_decay 是真正的 L2 正则化
optimizer = torch.optim.AdamW(model.parameters(), lr=0.001, weight_decay=0.01)
from torchvision import transforms
# 图像增强
augment = transforms.Compose([
transforms.RandomHorizontalFlip(p=0.5),
transforms.RandomRotation(15),
transforms.ColorJitter(brightness=0.2, contrast=0.2),
transforms.RandomCrop(32, padding=4),
])

验证集损失不再下降时停止训练,防止过拟合:

best_loss = float('inf')
patience = 5
patience_counter = 0
for epoch in range(epochs):
train_loss = train_one_epoch()
val_loss = validate()
if val_loss < best_loss:
best_loss = val_loss
torch.save(model.state_dict(), 'best_model.pt')
patience_counter = 0
else:
patience_counter += 1
if patience_counter >= patience:
print(f"Early stopping at epoch {epoch}")
break

标签不要 100% 确定,给错误类别留一点概率:

# 原始: [1, 0, 0] → 平滑后: [0.933, 0.033, 0.033]
criterion = nn.CrossEntropyLoss(label_smoothing=0.1)
class RegularizedMLP(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(
nn.Linear(784, 256),
nn.BatchNorm1d(256), # 归一化也是正则化
nn.ReLU(),
nn.Dropout(0.3), # Dropout
nn.Linear(256, 128),
nn.BatchNorm1d(128),
nn.ReLU(),
nn.Dropout(0.2),
nn.Linear(128, 10),
)
def forward(self, x):
return self.model(x)

💡 训练时 model.train() → Dropout 和 BatchNorm 生效;推理时 model.eval() → 自动关闭。