超参数 = 训练前设定的按钮,调得好差很多
学习率、Batch Size、早停、网格搜索、贝叶斯优化等调参实战技巧。
[toc]
超参数调优
1️⃣ 核心超参数一览
| 超参数 | 影响 | 典型范围 | 建议 |
|---|---|---|---|
| 学习率 (lr) | ⭐⭐⭐ 最重要 | 1e-5 ~ 1e-2 | 先用 1e-3 |
| Batch Size | ⭐⭐⭐ 训练速度+效果 | 16 ~ 512 | 能多大就多大 |
| Epoch | ⭐⭐ 训练程度 | 10 ~ 300 | 看验证集早停 |
| 优化器 | ⭐⭐⭐ 收敛方式 | Adam/SGD | 新手用 Adam |
| 权重衰减 (WD) | ⭐⭐ 防止过拟合 | 1e-5 ~ 1e-2 | 默认 1e-4 |
| Dropout | ⭐⭐ 防止过拟合 | 0.1 ~ 0.5 | 越大越防过拟合 |
| 网络层数 | ⭐⭐⭐ 模型容量 | 任务而定 | 从简单开始 |
| 隐藏层维度 | ⭐⭐ 模型容量 | 64 ~ 4096 | 能大则大但要防过拟合 |
2️⃣ 学习率 —— 最关键的超参数
学习率的影响
Loss
↑
| 太小 (1e-6)
| → 缓慢下降,可能卡在局部最优
|
| 刚好 (1e-3)
| → 快速稳定下降
|
| 太大 (1e-1)
| → Loss 震荡甚至发散
|
└─────────────────────────→ Step
学习率查找器 (Learning Rate Finder)
import torch
from torch_lr_finder import LRFinder
model = MyModel()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-7)
lr_finder = LRFinder(model, optimizer, criterion, device="cuda")
lr_finder.range_test(train_loader, end_lr=10, num_iter=100)
lr_finder.plot() # 找到 Loss 下降最快的区间
lr_finder.reset()实用技巧:
- 先用 LR Finder 找到合适的数量级
- 使用 余弦退火 或 分段衰减 调度
- 使用 预热 (Warmup) 避免初期不稳定
3️⃣ Batch Size 的选择
影响因素
| Batch Size | 优点 | 缺点 |
|---|---|---|
| 小 (16~64) | 泛化能力好,省显存 | 训练慢,梯度噪声大 |
| 大 (128~512+) | 训练快,梯度稳定 | 泛化可能下降,吃显存 |
线性缩放法则 (Linear Scaling Rule)
当 Batch Size 翻倍时,学习率也应翻倍(保持方差一致)
# 假设 batch_size=64 时 lr=1e-3
# 增大到 batch_size=256 时,lr ≈ 4e-34️⃣ 调优方法论
方法一:网格搜索 (Grid Search)
from sklearn.model_selection import ParameterGrid
param_grid = {
'lr': [1e-4, 3e-4, 1e-3],
'batch_size': [32, 64, 128],
'weight_decay': [0, 1e-4, 1e-3],
}
for params in ParameterGrid(param_grid):
accuracy = train_and_evaluate(**params)
print(params, accuracy)方法二:随机搜索 (Random Search)
import random
for _ in range(20):
lr = 10 ** random.uniform(-4, -2) # 对数均匀采样
batch_size = 2 ** random.randint(4, 7) # 16~128
weight_decay = 10 ** random.uniform(-5, -2)
accuracy = train_and_evaluate(lr, batch_size, weight_decay)方法三:贝叶斯优化
# pip install optuna
import optuna
def objective(trial):
lr = trial.suggest_float('lr', 1e-5, 1e-2, log=True)
batch_size = trial.suggest_categorical('batch_size', [32, 64, 128])
dropout = trial.suggest_float('dropout', 0.1, 0.5)
accuracy = train_and_evaluate(lr, batch_size, dropout)
return accuracy
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=50)
print(study.best_params) # 最佳参数5️⃣ 早停 (Early Stopping)
class EarlyStopping:
def __init__(self, patience=7, min_delta=0):
self.patience = patience
self.min_delta = min_delta
self.counter = 0
self.best_loss = None
self.early_stop = False
def __call__(self, val_loss):
if self.best_loss is None:
self.best_loss = val_loss
elif val_loss > self.best_loss - self.min_delta:
self.counter += 1
if self.counter >= self.patience:
self.early_stop = True
else:
self.best_loss = val_loss
self.counter = 0
# 使用
early_stopping = EarlyStopping(patience=5)
for epoch in range(EPOCHS):
val_loss = train()
early_stopping(val_loss)
if early_stopping.early_stop:
print(f"⏹️ 早停: epoch {epoch}")
break🎯 新手调优 checklist
| 步骤 | 做什么 |
|---|---|
| 1️⃣ | 先确保模型能过拟合一个小 batch(验证代码正确) |
| 2️⃣ | 用 LR Finder 找合适学习率 |
| 3️⃣ | 固定 lr,调 batch_size |
| 4️⃣ | 微调 weight_decay 和 dropout |
| 5️⃣ | 加入学习率调度和早停 |
| 6️⃣ | 尝试更深的网络或更大的隐藏层 |
| 7️⃣ | 数据增强 → 进一步提升上限 |
🔗 下一篇
→ 训练监控与可视化