Skip to content

正则化技术 (Regularization)


观察 L1/L2 正则化如何防止过拟合。增大多项式阶数会导致过拟合,增大 λ 可以抑制过拟合。

🛡️ 正则化可视化

真实函数无正则化L1 (Lasso)L2 (Ridge)
无正则化
训练 MSE: 0.033
测试 MSE: 0.046
L1 (Lasso)
训练 MSE: 0.175
测试 MSE: 0.179
L2 (Ridge)
训练 MSE: 0.163
测试 MSE: 0.177
权重分布对比
无正则化
非零权重: 8/9
L1 (Lasso)
非零权重: 4/9
L2 (Ridge)
非零权重: 9/9
💡 实验建议:
  • 增大多项式阶数观察过拟合(红线剧烈波动)
  • 增大λ观察正则化如何平滑曲线
  • L1产生稀疏权重(部分权重=0)
  • L2让所有权重变小但非零

💡 紫点=训练数据, 虚线=真实函数 sin(πx)


一句话定义:正则化是一类限制模型复杂度的技术,目的是防止模型在训练数据上表现太好(过拟合),而在新数据上表现很差(泛化能力差)。

常见正则化方法:

  • L1/L2 正则化: 在损失函数中添加权重惩罚项
  • Dropout: 训练时随机”关闭”部分神经元
  • 数据增强: 人工扩充训练数据
  • 早停 (Early Stopping): 在验证集性能开始下降时停止训练

  • 过拟合 (Overfitting):学生把课本例题死记硬背,考试遇到稍微变化的题目就不会。模型”背住”了训练数据,但没学到规律。
  • 欠拟合 (Underfitting):学生连例题都没看懂,基础知识都没掌握。模型太简单,连训练数据都拟合不好。
  • 正则化:老师限制学生只能看例题 3 遍,逼迫学生去理解方法而不是死记答案。

偏差-方差权衡 (Bias-Variance Tradeoff)

Section titled “偏差-方差权衡 (Bias-Variance Tradeoff)”
欠拟合刚刚好过拟合
偏差 (Bias)
方差 (Variance)
训练误差极低
测试误差

正则化的目标:在偏差和方差之间找到平衡点,使测试误差最小。


在损失函数中添加权重的平方和:

L2 正则化
Ltotal=Ldata+λiwi2\mathcal{L}_{total} = \mathcal{L}_{data} + \lambda \sum_i w_i^2
  • λ\lambda: 正则化强度 (超参数)
  • 效果:让权重趋向于小而分散
  • 梯度更新:wwη(L+2λw)w \leftarrow w - \eta(\nabla\mathcal{L} + 2\lambda w)
  • 又叫 Weight Decay(权重衰减)

使用权重的绝对值之和:

L1 正则化
Ltotal=Ldata+λiwi\mathcal{L}_{total} = \mathcal{L}_{data} + \lambda \sum_i |w_i|
  • 效果:让部分权重变成精确的 0(稀疏性)
  • 可用于特征选择(自动筛掉不重要的特征)
  • 缺点:在 0 点不可导,需要特殊处理

训练时以概率 pp 随机将神经元输出置为 0:

Dropout
h=hm,mBernoulli(1p)h' = h \cdot m, \quad m \sim \text{Bernoulli}(1-p)
  • pp: drop 概率(通常 0.1-0.5)
  • 训练时:随机丢弃,输出除以 (1p)(1-p) 保持期望不变
  • 推理时:不丢弃,直接使用全部神经元
  • 效果:类似训练了多个子网络的集成
特性L1 (Lasso)L2 (Ridge)
惩罚形式w\|w\|w2w^2
权重分布稀疏(很多 0)小而分散
特征选择✅ 自动
计算不可导点需处理处处可导
使用场景高维稀疏数据通用

import torch
import torch.nn as nn
# ===== L2 正则化 (Weight Decay) =====
# PyTorch 优化器内置支持
model = nn.Linear(10, 1)
optimizer = torch.optim.Adam(
model.parameters(),
lr=0.001,
weight_decay=0.01 # L2 正则化强度
)
# ===== L1 正则化 (手动添加) =====
def l1_regularization(model, lambda_l1=0.001):
l1_loss = 0
for param in model.parameters():
l1_loss += torch.abs(param).sum()
return lambda_l1 * l1_loss
# 训练循环中
loss = criterion(output, target)
loss += l1_regularization(model) # 添加 L1 项
loss.backward()
# ===== Dropout =====
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(784, 256)
self.dropout = nn.Dropout(p=0.5) # 50% drop 概率
self.fc2 = nn.Linear(256, 10)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = self.dropout(x) # 训练时生效,eval 时自动关闭
x = self.fc2(x)
return x
model = MyModel()
model.train() # Dropout 生效
model.eval() # Dropout 关闭
# ===== 早停 (Early Stopping) =====
class EarlyStopping:
def __init__(self, patience=5, min_delta=0):
self.patience = patience
self.min_delta = min_delta
self.counter = 0
self.best_loss = float('inf')
self.should_stop = False
def __call__(self, val_loss):
if val_loss < self.best_loss - self.min_delta:
self.best_loss = val_loss
self.counter = 0
else:
self.counter += 1
if self.counter >= self.patience:
self.should_stop = True
# 使用
early_stop = EarlyStopping(patience=5)
for epoch in range(100):
train_loss = train_one_epoch()
val_loss = validate()
early_stop(val_loss)
if early_stop.should_stop:
print(f"Early stopping at epoch {epoch}")
break



CS231n Regularization

Stanford 课程正则化讲义

阅读

Dropout 原论文

Srivastava et al., 2014

阅读

AdamW 论文

Decoupled Weight Decay Regularization

阅读