文章目录
-
- [**1. Warmup 的核心作用**](#1. Warmup 的核心作用)
-
- [**为什么要 Warmup?**](#为什么要 Warmup?)
- **工作流程**:
- [**2. Warmup_epochs 与哪些因素相关?**](#2. Warmup_epochs 与哪些因素相关?)
-
- [**因素1:Batch Size(最相关!)**](#因素1:Batch Size(最相关!))
- **因素2:模型大小和复杂度**
- **因素3:初始学习率(lr0)**
- **因素4:优化器类型**
- **因素5:总训练周期**
- [**3. 不同场景下的 Warmup 设置**](#3. 不同场景下的 Warmup 设置)
-
- [**场景1:小批量训练(Batch Size ≤ 32)**](#场景1:小批量训练(Batch Size ≤ 32))
- [**场景2:大批量训练(Batch Size > 128)**](#场景2:大批量训练(Batch Size > 128))
- **场景3:迁移学习/微调**
- **场景4:从头训练**
- [**4. Warmup 的不同策略**](#4. Warmup 的不同策略)
-
- [**线性 Warmup(最常用)**](#线性 Warmup(最常用))
- [**指数 Warmup**](#指数 Warmup)
- [**余弦 Warmup(结合余弦衰减)**](#余弦 Warmup(结合余弦衰减))
- [**YOLOv5/v8 中的实际实现**](#YOLOv5/v8 中的实际实现)
- [**5. 如何确定最佳的 Warmup_epochs?**](#5. 如何确定最佳的 Warmup_epochs?)
-
- **方法1:观察训练曲线诊断**
- **方法2:网格搜索**
- [**方法3:基于 Batch Size 的经验公式**](#方法3:基于 Batch Size 的经验公式)
- [**6. 与其他参数的协调**](#6. 与其他参数的协调)
-
- **与学习率衰减的配合**
- **与动量的配合**
- [**与 BatchNorm 的配合**](#与 BatchNorm 的配合)
- [**7. 特殊情况的处理**](#7. 特殊情况的处理)
- [**8. 调试和监控 Warmup 效果**](#8. 调试和监控 Warmup 效果)
- [**9. 最佳实践总结**](#9. 最佳实践总结)
warmup_epochs 是一个非常关键的超参数,它控制训练初期的学习率预热策略。让我详细解释它的作用和设置原则:
1. Warmup 的核心作用
为什么要 Warmup?
- 稳定训练初期:模型参数随机初始化,直接使用大学习率可能导致梯度爆炸/震荡
- 帮助 BatchNorm 统计:让 BatchNorm 层积累足够的统计量(均值和方差)
- 避免早期过拟合:小学习率开始,让模型先探索平滑的损失曲面
- 梯度方向校准:初期梯度方向可能不准,小学习率可减少错误更新的影响
工作流程:
┌─────────────────────────────────────────────┐
│ Warmup 阶段(学习率从0逐渐增加) │
├─────────────────────────────────────────────┤
│ epoch 0: lr = lr0 * 0.001 │
│ epoch 1: lr = lr0 * 0.33 │
│ epoch 2: lr = lr0 * 0.67 │
│ epoch 3: lr = lr0 * 1.0 ← warmup结束 │
│ epoch 4+: 开始正常衰减(余弦/线性衰减) │
└─────────────────────────────────────────────┘
2. Warmup_epochs 与哪些因素相关?
因素1:Batch Size(最相关!)
python
# Batch Size 与 Warmup 的关系
warmup_epochs ≈ k * sqrt(batch_size)
# 经验公式:
if batch_size <= 16:
warmup_epochs = 1-3
elif batch_size <= 64:
warmup_epochs = 3-5
elif batch_size <= 256:
warmup_epochs = 5-10
elif batch_size > 256:
warmup_epochs = 10-20 # 或使用 warmup_steps
因素2:模型大小和复杂度
python
# 模型越大越深,需要更长的 warmup
model_config = {
'YOLOv5n': {'warmup': 2-3}, # 小模型
'YOLOv5s': {'warmup': 3-4},
'YOLOv5m': {'warmup': 4-5},
'YOLOv5l': {'warmup': 5-7},
'YOLOv5x': {'warmup': 7-10}, # 大模型
'ViT-Base': {'warmup': 10-20}, # Transformer需要更长
'ResNet-152': {'warmup': 5-8},
}
因素3:初始学习率(lr0)
python
# lr0 越大,需要越长的 warmup
lr0_warmup_mapping = {
0.001: 1-2, # 很小的 lr0,可以不用或很短的 warmup
0.01: 3-5, # 默认值
0.05: 5-8, # 较大 lr0
0.1: 8-12, # 很大 lr0,需要充分预热
}
因素4:优化器类型
python
optimizer_warmup = {
'SGD': 5-8, # SGD对学习率敏感,需要较长warmup
'Adam': 3-5, # Adam自适应,可稍短
'AdamW': 3-5, # AdamW类似Adam
'LAMB': 8-15, # LAMB用于大batch,需长warmup
'RAdam': 0, # RAdam内置warmup,可设为0
}
因素5:总训练周期
python
# 占总训练周期的比例(通常 5-15%)
total_epochs = 300
warmup_epochs = int(total_epochs * 0.05) # 5% = 15 epochs
# 或
warmup_epochs = int(total_epochs * 0.1) # 10% = 30 epochs
3. 不同场景下的 Warmup 设置
场景1:小批量训练(Batch Size ≤ 32)
yaml
# 典型配置
batch_size: 16-32
warmup_epochs: 2-4
warmup_momentum: 0.8 # 动量也从低值开始增加
warmup_bias_lr: 0.1 # bias学习率也预热
场景2:大批量训练(Batch Size > 128)
yaml
# 大批量需要更长的预热
batch_size: 256
warmup_epochs: 10-20
# 或使用 warmup_steps(更精确)
warmup_steps: 2000 # 相当于约8个epoch(每个epoch250步)
场景3:迁移学习/微调
yaml
# 预训练模型,可缩短warmup
weights: 'pretrained.pt'
warmup_epochs: 1-2 # 因为权重已经较好,不需要长预热
lr0: 0.001 # 较小的初始学习率
场景4:从头训练
yaml
# 随机初始化,需要充分预热
warmup_epochs: 5-10
warmup_momentum: 0.8
warmup_bias_lr: 0.1
4. Warmup 的不同策略
线性 Warmup(最常用)
python
# 线性从 warmup_factor 增加到 1.0
warmup_factor = 0.1 # 开始学习率 = lr0 * 0.1
current_lr = lr0 * (warmup_factor + (1 - warmup_factor) * epoch/warmup_epochs)
指数 Warmup
python
# 指数增长
warmup_factor = 0.001
current_lr = lr0 * warmup_factor ** (1 - epoch/warmup_epochs)
余弦 Warmup(结合余弦衰减)
python
# 使用余弦函数进行warmup
import math
current_lr = lr0 * 0.5 * (1 - math.cos(math.pi * epoch / warmup_epochs))
YOLOv5/v8 中的实际实现
python
# YOLO中的warmup实现(简化版)
def warmup_lr(epoch, warmup_epochs, lr0):
if epoch < warmup_epochs:
# 学习率预热
lr = lr0 * (epoch / warmup_epochs) ** 2 # 平方增长
# 动量预热(从低到高)
momentum = 0.9 - 0.4 * (epoch / warmup_epochs)
else:
lr = lr0 # 正常衰减
momentum = 0.9
return lr, momentum
5. 如何确定最佳的 Warmup_epochs?
方法1:观察训练曲线诊断
python
def diagnose_warmup(train_loss_history):
"""
通过训练损失判断warmup是否合适
"""
early_loss = train_loss_history[:warmup_epochs]
if 损失震荡剧烈:
# warmup不足
建议: 增加warmup_epochs 或 减小warmup_factor
elif 损失下降太慢:
# warmup太长或学习率太小
建议: 减少warmup_epochs 或 增大warmup_factor
elif 损失平稳下降:
# warmup设置合适
保持当前设置
方法2:网格搜索
python
warmup_candidates = [0, 1, 2, 3, 5, 8, 10, 15]
warmup_factors = [0.01, 0.1, 0.2, 0.5]
best_combination = None
best_val_acc = 0
for warmup_epochs in warmup_candidates:
for warmup_factor in warmup_factors:
# 训练并评估
val_acc = train_and_evaluate(warmup_epochs, warmup_factor)
if val_acc > best_val_acc:
best_val_acc = val_acc
best_combination = (warmup_epochs, warmup_factor)
方法3:基于 Batch Size 的经验公式
python
def calculate_warmup(batch_size, total_epochs=300, model_size='medium'):
"""根据batch_size计算warmup"""
base_warmup = {
'small': 2, # 小模型
'medium': 3, # 中等模型
'large': 5, # 大模型
}[model_size]
# 基于batch_size调整
batch_factor = max(1, batch_size / 64) ** 0.5
warmup_epochs = int(base_warmup * batch_factor)
# 限制范围
warmup_epochs = min(warmup_epochs, total_epochs * 0.15) # 不超过总epochs的15%
warmup_epochs = max(1, warmup_epochs) # 至少1个epoch
return warmup_epochs
6. 与其他参数的协调
与学习率衰减的配合
yaml
# 示例:总训练300epochs的协调设置
lr0: 0.01
lrf: 0.01
warmup_epochs: 3
# 训练过程:
# 1. epoch 0-2: warmup阶段,lr从0.001线性增加到0.01
# 2. epoch 3-299: 正常衰减,从0.01降到0.0001
与动量的配合
yaml
# 通常动量也需要warmup
warmup_momentum: 0.8 # 从0.8开始
momentum: 0.937 # 最终动量
# 训练过程:
# warmup阶段:动量从warmup_momentum增加到momentum
# 正常阶段:保持momentum
与 BatchNorm 的配合
python
# 如果使用SyncBatchNorm(分布式训练)
# 需要更长的warmup让统计量稳定
if sync_bn: # 同步BatchNorm
warmup_epochs = max(warmup_epochs, 10)
7. 特殊情况的处理
情况1:训练中断后恢复
yaml
# 从检查点恢复时,通常不需要warmup
resume: path/to/checkpoint.pt
warmup_epochs: 0 # 或者设置为很小的值
情况2:极短训练周期
yaml
# 如果只训练很少的epochs
epochs: 50
warmup_epochs: 1 # 只预热1个epoch,因为总时间很短
情况3:多阶段训练
python
# 阶段1:大学习率训练
stage1 = {'epochs': 100, 'lr0': 0.1, 'warmup_epochs': 10}
# 阶段2:小学习率微调
stage2 = {'epochs': 50, 'lr0': 0.001, 'warmup_epochs': 2}
情况4:不同层不同学习率
python
# backbone使用更小的学习率和更长的warmup
backbone_params = {
'lr': 0.001,
'warmup_epochs': 10
}
head_params = {
'lr': 0.01,
'warmup_epochs': 3
}
8. 调试和监控 Warmup 效果
监控脚本
python
import matplotlib.pyplot as plt
def plot_warmup_effect(train_loss, val_loss, warmup_epochs):
"""绘制warmup阶段的效果"""
plt.figure(figsize=(12, 4))
# 损失曲线
plt.subplot(1, 2, 1)
plt.plot(train_loss, label='Train Loss')
plt.plot(val_loss, label='Val Loss')
plt.axvline(x=warmup_epochs, color='r', linestyle='--',
label=f'Warmup End (epoch {warmup_epochs})')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.grid(True)
# Zoom in warmup阶段
plt.subplot(1, 2, 2)
plt.plot(train_loss[:warmup_epochs*2], label='Train Loss')
plt.plot(val_loss[:warmup_epochs*2], label='Val Loss')
plt.axvline(x=warmup_epochs, color='r', linestyle='--')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Warmup Phase Zoom')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
日志分析
bash
# 训练日志中观察warmup阶段
Epoch GPU_mem box_loss obj_loss cls_loss Instances Size LR
0/299 5.8G 0.1 0.05 0.03 32 640 0.00001 # warmup开始
1/299 5.8G 0.08 0.04 0.025 32 640 0.00333
2/299 5.8G 0.06 0.03 0.02 32 640 0.00667
3/299 5.8G 0.05 0.025 0.018 32 640 0.01 # warmup结束
4/299 5.8G 0.045 0.022 0.016 32 640 0.0099 # 开始衰减
9. 最佳实践总结
推荐设置表格
| 场景 | Batch Size | Warmup Epochs | Warmup Factor | 说明 |
|---|---|---|---|---|
| 小模型/小数据 | ≤16 | 1-2 | 0.1 | 短warmup足够 |
| 标准训练 | 32-64 | 3-5 | 0.1 | 默认推荐 |
| 大批量训练 | 128-256 | 8-15 | 0.01-0.05 | 需要充分预热 |
| 大模型/Transformer | 任何 | 10-20 | 0.01 | 模型复杂需长预热 |
| 迁移学习 | 任何 | 1-3 | 0.5-1.0 | 权重已预训练 |
| 分布式训练 | 任何 | 增加50% | 0.01-0.1 | SyncBN需要稳定 |
经验法则
- Batch Size 法则:warmup_epochs ≈ sqrt(batch_size / 32) × 3
- 比例法则:warmup_epochs ≈ 总epochs的5-10%
- 学习率法则:lr0越大,warmup应该越长
- 安全法则:宁长勿短,过长的warmup通常比过短更安全
最终建议
yaml
# 对于大多数情况的安全设置
warmup_epochs: 3
warmup_momentum: 0.8
warmup_bias_lr: 0.1
# 如果你不确定:
# 1. 先从默认值(3个epoch)开始
# 2. 观察训练初期的损失曲线
# 3. 如果震荡就增加warmup_epochs
# 4. 如果下降太慢就减少warmup_epochs
记住:最佳的 warmup_epochs 值需要通过实验确定,因为它与你的特定任务、数据、模型和硬件都密切相关。监控训练初期的损失曲线是最好的诊断方法。