为什么训练需要技巧?
上一章我们学习了损失函数——它告诉模型“你错了多少”。但知道错了多少和能够正确地把错误改正过来,是两回事。
训练一个神经网络就像炖牛肉——火候太大会烧焦(发散),火候太小炖不烂(收敛慢),调料不对味道奇怪(过拟合)。本章就是“炖牛肉宝典”。
具体来说,我们将学习:
- 学习率:步长大小如何调整?热身(温炉) · 阶梯衰减 · 余弦衰减
- Batch Size:每步用多少数据计算更新?大vs小的影响
- 正则化(L1/L2):给损失加“罚款”避免过拟合
- Dropout:训练时随机抛弃神经元,迫使网络学习冗余表示
- 早期停止:在过拟合前自动停下来
学习率是什么?从头学起
学习率 (Learning Rate, α) 是训练中最重要的超参数。
在梯度下降中:
Wₜ₊₁ = Wₜ - α · ∇L(Wₜ)
学习率 α 决定了“每步走多远”。
日常比喻:你在山谷里要找到最低点。学习率就是你的步子大小:
- 步子太大 (α=1.0):跨过山谷,跳来跳去,发散
- 步子適中 (α=0.01):稳步下降,快速到达底部
- 步子太小 (α=0.00001):爬得极慢,可能陷入局部最优
一个典型的实验事实:
在CIFAR-10数据集上,用ResNet-50训练:
- α=0.1: 发散(loss变NaN)
- α=0.01: 50轮达到75%准确率
- α=0.001: 50轮只到60%,还在慢慢下降
- α=0.0001: 50轮只到50%,太慢
学习率策略:Warmup + 衰减
在实战中,我们不会用固定的学习率,而是让它随训练进程动态调整。
1. Warmup(热身)
开始时学习率从0慢慢升到目标值。原因:初始化的权重是随机的,刚开始梯度不稳定;大学习率在开始阶段可能会将参数射到很远的坏区域。
GPT-3用了375步Warmup(从0到0.6×10⁻⁴)。
α(t) = αₜₒₜ × (t / T_warmup) — 线性升温
2. 阶梯衰减 (Step Decay)
每T步将学习率乘以衰减因子。
α(t) = α₀ × γ^{floor(t / T)}
例:α₀=0.01, γ=0.1, T=30轮→50轮时0.01, 30轮后0.001, 60轮后0.0001
3. 余弦衰减 (Cosine Decay)
学习率按余弦函数从最大值平滑下降到最小值。最常用。
α(t) = α_min + 0.5×(α_max - α_min)×(1 + cos(π×t/T_max))
优点:平滑下降,报文当中可以学得更好。
4. 多兹马减速(Cosine with Restarts)
学习率周期性重置,每次重置后训练“跳出”局部最优找更好的解。
实战建议:
- Adam默认学习率0.001,通常无需Warmup
- SGD+Momentum建议+Cosine Decay+热身
- Transformer皆需Warmup,因Adam初期方差估计不稳
学习率策略参数对照表
| 策略 | 关键参数 | 适用场景 | 备注 |
|---|---|---|---|
| 固定学习率 | α | 简单小模型 | 不建议大模型 |
| Warmup | T_warmup, α_target | Transformer/Large Batch | 典型500-4000步 |
| 阶梯衰减 | α₀, γ(0.1), T(30) | 传统CV任务 | 简单粗糙 |
| 余弦衰减 | α_max, α_min, T_max | 最常用 | 平滑下降 |
| 多兹马减速 | α_max, T_0, T_mult | 避免局部最优 | SGD常用 |
| 指数衰减 | α₀, γ(0.95/epoch) | 收敛稳定 | 每轮乘γ |
学习率数值示例
问题:W=5.0, L(W)=W², ∇L=2W=10。分别用α=0.1, 0.5, 2.0更新一步,观察结果。
α=0.1(合适):
Wₙ₊₁ = 5.0 - 0.1×10 = 4.0 → L=16↓(下降4→0)
α=0.5(较大):
Wₙ₊₁ = 5.0 - 0.5×10 = 0.0 → L=0(一步到达最优点)
α=2.0(过大):
Wₙ₊₁ = 5.0 - 2.0×10 = -15.0 → L=225(越过最优点,损失反而增大4.5倍!)
实战中:训练ResNet-34于ImageNet,使用阶梯衰减:
α₀=0.1,每30轮×0.1 Epoch 1-30: α=0.1 → Top-1 error 从 100% → 52% Epoch 31-60: α=0.01 → Top-1 error → 42% Epoch 61-90: α=0.001 → Top-1 error → 40%
实战练习
Q1:假设你在训练一个GPT模型,学习率设为0.001,第100步时loss突然变NaN。可能原因是什么?怎么修复?
A1:学习率过大导致发散。补救:(1)降低学习率(如0.0001);(2)添加Warmup;(3)加梯度裁剪。
Q2:一个余弦衰减策略:α_max=0.01, α_min=0.00001, T_max=100轮。计算t=0, 25, 50, 100轮时的学习率。
A2:t=0: 0.01(最大)
t=25: 0.00001 + 0.5×(0.01-0.00001)×(1+cos(π×25/100))
= 0.00001 + 0.5×0.00999×(1+cos(π/4))
= 0.00001 + 0.5×0.00999×(1+0.707) = 0.00854
t=50: 0.00500
t=100: 0.00001Q3:SGD训练中如果loss下降很慢但很稳定,应该怎么办?
A3:学习率可能太小。尝试倍增学习率或加Momentum。另外检查是否数据标准化不对。
查看答案
A1: 学习率过大导致发散。补救:降低学习率+Warmup+gradient clipping
A2: t=0: 0.01, t=25: 0.00854, t=50: 0.00500, t=100: 0.00001
A3: 学习率太小。测试用线性扫描找最佳学习率范围
Batch Size是什么?从头学起
Batch size = 每次反向传播用的样本数。
正在更新权重前,我们需要累积多少个样本的梯度?
三种模式:
- Batch GD(全数据):batch_size=N。稳定但慢,实际不用。
- SGD(单样本):batch_size=1。快但噪声大,可以跳出局部最优但不稳定。
- Mini-batch(小批量):batch_size=16/32/64/128/256。实战标配,兼顾速度和稳定性。
为什么Mini-batch最好?
- 梯度是N个样本的平均,batch大小越大梯度越准确
- 但太大的batch可能导致“锐利最小值”问题——收敛到sharp minima(泛化差)
- GPU内存限制batch大小上限
几个重要事实:
- batch_size×学习率保持不变原则:batch翻倍→学习率也翻倍(linear scaling rule)
- GPT-3 batch_size=3.2M tokens(多GPU汇总)
- ImageNet上2K batch_size与8K准确率相同,但训练时间减半
Batch Size参数与影响
大batch的优势:
- 梯度更准确,收敛进程更平滑
- 充分利用GPU并行计算(向量化)
- 总训练时间可能更短
小batch的优势:
- 噪声可以帮助跳出局部最优
- 泛化性能更好(解释1:小batch向量更像治疗器的Brownian motion)
- 内存占用少,可训练更大模型
Batch size对巡回的影响:
巡回=epoch (1轮 = 全数据走一遍)。batch_size越大,每轮更新次数=N/batch_size越少。
例:N=50000, batch_size=32 → 1563 updates/epoch
batch_size=256 → 195 updates/epoch
Batch Size参数对照表
| Batch Size | 稳定性 | 速度 | 泛化 | 内存 | 适用场景 |
|---|---|---|---|---|---|
| 1 (SGD) | 很差 | 很快(per step) | 很好 | 极低 | Online learning |
| 8-16 | 低 | 快 | 好 | 低 | GAN/RL/不稳定场景 |
| 32-64 | 中 | 较快 | 良好 | 中 | 最常用,建议默认 |
| 128-256 | 高 | 中 | 中 | 较高 | 大数据集/CV任务 |
| 512-1024 | 很高 | 慢 | 偏低 | 很高 | BatchNorm常用,需多GPU |
| 4096+ | 极高 | 极慢 | 偏低 | 极高 | Large batch training(需warmup+特殊调参) |
Batch Size数值示例
问题:数据集N=1000,学习率α=0.01,计算batch_size=32和256时每轮的更新次数,以及同样epoch数下的最终损失趋势。
Step 1: 计算每轮更新次数
batch_size=32: 1000/32 = 31.25 → 31 updates/epoch batch_size=256: 1000/256 = 3.91 → 3 updates/epoch
同样10轮:
batch=32: 310 updates batch=256: 30 updates
大batch更新次数远少于小batch,但每步看到更多数据。
Step 2: 对数据的视角
batch=32时30步后看到所有数据一遝
batch=256时第1步看到256个数据,但看完全部1000需要4步
Step 3: 大batch的Linear Scaling Rule
batch从32→256(×8),学习率应从0.01→0.08保持效果相同。但实际上需要Warmup避免开始时梯度不稳定。
实战练习
Q1:你用VGG训练CIFAR-10,batch_size=64时显卡翁内存占用约80%。想提高训练速度是应该增大还是减小batch?为什么?
A1:显卡内存不足时不能增大batch。可以用积累梯度(accumulate gradient)——多歡小batch后再更新权重。或用gradient checkpoint减少内存消耗。
Q2:batch_size=32训练BERT-Large能装下4根显卡,每步用0.5s。如果batch_size=64呢?
A2:batch翻倍→1根显卡内存不足,需要2根显卡并行计算,通信开销可能让速度只提升~1.5倍。
Q3:假设你发现验证集准确率随batch_size增大而下降,这是为什么?怎么解决?
A3:大batch收敛到sharp minima(泛化差)。解决:(1)增大学习率并加Warmup;(2)加正则化(L2/Dropout/BatchNorm);(3)用Sampling SGD替代
查看答案
A1: 用gradient accumulation或checkpointing,不能直接增大batch
A2: batch=64需多卡,通信开销减缓显卡数直线加成
A3: sharp minima问题。增大学习率+Warmup+正则化
正则化是什么?从头学起
正则化 = 给损失函数加“罚款”,让模型不要太复杂。
过拟合的核心问题:模型只记住了数据而没学到规律。正则化通过增加一个罚款项《λ·R(W)》来控制模型复杂度。
日常比喻:如果老师说
“如果你把答案写得超长,我会扣分”,学生就不会无端拉长答案。正则化就是这个“超长扣分”。
公式:
L_total = L_data + λ · R(W)
- L_data: 原来的损失(如CrossEntropy, MSE)
- R(W): 权重的“复杂度”
- λ: 正则化强度——越大罚款越重,模型越简单
三种常见正则化:
- L1(Lasso):R(W) = ∑|w_i|。推向稀疏(许多权重变为0)。
- L2(Ridge / 权重衰减):R(W) = ½∑w_i²。权重趋近0但不为0。
- Elastic Net(弹性网):R(W) = r·∑|w_i| + (1-r)·½∑w_i²。结合L1+L2。
L1 vs L2:详细分析
L2正则化(Weight Decay)
L_total = L_data + λ/2 · ∑w_i²
梯度:∂L/∂w_i = ∂L_data/∂w_i + λ·w_i
更新的时候:
w_i → w_i - α·(∂L_data/∂w_i + λ·w_i)
w_i → w_i·(1 - αλ) - α·∂L_data/∂w_i
看到有一个“(1 - αλ)”的衰减系数——这就是“Weight Decay”名字的由来。
L1正则化(Lasso)
L_total = L_data + λ · ∑|w_i|
梯度:∂L/∂w_i = ∂L_data/∂w_i + λ·sign(w_i)
罚款不取决于权重大小,只取决于符号。这导致小权重被拉到0——特征选择。
关键区别:
- L2:权重趋近0但不等于0。适合所有特征都可能有用的场景。
- L1:权重变为0——特征选择。适合有许多无用特征。
- 全局最优解唯一性:L2有解析解;L1可能多个最优解。
正则化参数对照表
| 类型 | 公式 | 罚款方式 | 稀疏 | ̣ 范围 | 适用场景 |
|---|---|---|---|---|---|
| L2 (Weight Decay) | ½∑w² | 权重越大罚款越重 | ❌ 不为0 | 0.0001~0.01 | 神经网络默认 |
| L1 (Lasso) | ∑|w| | 绝对值罚款 | ✅ 为0 | 0.0001~0.01 | 特征选择/稀疏模型 |
| Elastic Net | r·L1+(1-r)·L2 | 组合 | 部分 | λ=0.0001~0.01, r=0.5 | 特征多且相关 |
正则化数值示例
问题:设有一个某一权重 w=2.0,原始梯度∂L_data/∂w=0.5,学习率α=0.1。计算不加正则化、加L2(λ=0.01)、加L1(λ=0.01)时的更新后权重。
无正则化:
w' = 2.0 - 0.1×0.5 = 2.0 - 0.05 = 1.95
L2正则化 (λ=0.01):
∂L/∂w = 0.5 + 0.01×2.0 = 0.5 + 0.02 = 0.52 w' = 2.0 - 0.1×0.52 = 2.0 - 0.052 = 1.948w' = 2.0×(1-0.1×0.01) - 0.1×0.5 = 1.998 - 0.05 = 1.948
L2加了额外的-0.002更新。权重越大这个修正越明显。
L1正则化 (λ=0.01):
∂L/∂w = 0.5 + 0.01×sign(2.0) = 0.5 + 0.01 = 0.51 w' = 2.0 - 0.1×0.51 = 2.0 - 0.051 = 1.949
对比(多步走向稳态):
Epoch | 无正则化 | L2(λ=0.01) | L1(λ=0.01) 0 | 2.000 | 2.000 | 2.000 10 | 1.500 | 1.492 | 1.490 50 | 0.750 | 0.735 | 0.721 100 | 0.375 | 0.359 | 0.310 500 | 0.012 | 0.008 | 0.000(L1达到0!)
L1的稀疏效果明显——小权重被拉到0。L2趋近0但不等于0。
实战练习
Q1:训练一个100层ResNet时,发现训练loss下降正常但验证loss在某节点开始上升。应该用什么正则化?λ应该设多大?
A1:经典过拟合。建议用L2 (Weight Decay),设置λ=0.0001开始,按十倍调整直到验证集性能挺住。PyTorch中: optimizer=SGD(params, lr=0.1, weight_decay=1e-4)
Q2:你的数据集有20000个特征但只有1000个样本。应该选择L1还是L2?为什么?
A2:L1。因为大多数特征可能无用,L1能将无用特征对应的权重压到0,实现特征选择。同时有助于避免维度灾难。
Q3:Adam优化器中的weight_decay和L2正则化是同一回事吗?
A3:不是。Adam中直接加L2在梯度中会与自适应学习率交互,导致正则化效果偏离。AdamW提出分离weight decay和梯度更新——按Decoupled Weight Decay更新。建议用AdamW替Adam。
查看答案
A1: L2正则化,weight_decay从1e-4开始调
A2: L1,因为稀疏特征选择在p≫n时最有用
A3: 不同。AdamW的weight decay是解耦的更新,而非在梯度中加L2项
Dropout是什么?从头学起
Dropout = 训练时随机“抛弃”一些神经元,让网络更健壮。
2012年Hinton发明。怎么做:每次训练迭代时,以概率 p 随机将某些神经元的输出设为0。
日常比喻:如果你只会用一只脚踩自行车,按你的脚你就剳车。但如果训练时随机抵你的一只脚,你就会学会用另一只脚。最终你两只脚都能骑得很好——这就是Dropout的本质。
数学表示:
训练时: r ~ Bernoulli(p) → 输出 = r × h / (1-p) 测试时: 输出 = h (scaling by keep_prob)
为什么要除以(1-p)?因为训练时只有(1-p)的神经元在工作,为了让测试时期望值与训练时保持一致,需要做这个缩放。
Dropout变种与实践
1. 标准Dropout (p=0.5)
隐藏层用p=0.5,输入层p=0.2~0.3。最常用。
2. 空间Dropout (Spatial Dropout)
CNN中用——整个通道随机置零而不是像素。因为CNN中相邻像素高度相关,抵单个像素效果不好。
3. AlphaDropout
SELU激活函数的配套Dropout。保持输出的均值和方差不变。
4. Monte Carlo Dropout
测试时也保留Dropout,多次前向传播获得不确定性估计。这是一种Bayesian近似。
5. 递进Dropout
深层用p=0.5,浅层用p=0.1。因为深层参数更多,更容易过拟合。
黄金规则:
- 隐藏层Dropout p=0.5——最稳妥。模型过拟合时提高到0.5,不过拟合时降低到0.2
- 输入层Dropout p=0.2~0.3——只抛弃少量输入特征
- Dropout与BatchNorm一般不同时使用(但可以)
- CNN层少用Dropout(用BatchNorm+Data Aug替代)
- Transformer/GPT不用Dropout(大模型用正则化+数据质量控制)
Dropout参数对照表
| 类型 | 默认p | 适用层 | 特点 | 适用场景 |
|---|---|---|---|---|
| 标准Dropout | 0.5 | 全连接隐藏层 | 最简单常用 | MLP/FC网络 |
| 输入Dropout | 0.2-0.3 | 输入层 | 保护输入特征 | 噪声数据 |
| 空间Dropout | 0.2-0.5 | CNN卷积层 | 整通道置零 | CNN |
| AlphaDropout | 0.05-0.1 | SELU激活层 | 保持均值方差 | Self-normalizing网络 |
| MC Dropout | 同训练 | 任意 | 测试时保留 | 不确定性估计 |
Dropout数值示例
问题:一个隐藏层有4个神经元,输出向量h=[1.0, 2.0, 3.0, 4.0],Dropout概率p=0.5。测试时和两次训练时的输出是多少?
测试时(不抛弃):
输出 = h = [1.0, 2.0, 3.0, 4.0]
训练时第1次迭代:
Bernoulli(0.5) mask = [1,0,1,0]
原始输出 = [1.0, 0.0, 3.0, 0.0]
缩放 = [1.0/(1-0.5), 0, 3.0/(1-0.5), 0]
= [2.0, 0.0, 6.0, 0.0]训练时第2次迭代:
Bernoulli(0.5) mask = [0,1,0,1] 输出 = [0.0, 4.0, 0.0, 8.0]
观察:
- 每次训练只用约50%的神经元
- 第1次用第1,3个神经元,第2次用第2,4个
- 缩放确保期望值相同:E[2.0,0,6.0,0]=[1.0,0,3.0,0]
- 最终网络学习到的是所有神经元的“平均”表示,更健壮
实战练习
Q1:你的MLP在训练集上准确率99.5%,但验证集只有85%,差距14.5%。应该加Dropout吗?用多大概率?
A1:经典的过拟合,应该加Dropout。隐藏层p=0.5,输入层p=0.2开始调整。可以同时加L2(λ=0.0001)和Data Augmentation。
Q2:为什么GPT等Transformer模型不用Dropout?
A2:(1)大模型尾部网络层力量大,Dropout可能会影响信息流递;(2)大数据量已经提供天然正则化;(3)更常用兆义正则化和权重衰减。
Q3:Dropout训练后的模型在测试时输出与训练时的“平均网络”有何关系?
A3:Dropout可以看作大量子网络的集成学习(ensemble)。训练时从2ⁿ个子网络中随机采样一个,测试时的输出等价于所有子网络的平均。这就是为什么Dropout能提升泛化性能。
查看答案
A1: 是的。隐藏层 Dropout p=0.5,输入层 p=0.2
A2: 大数据量+兆义正则化已足够,Dropout在大模型中效果不显著
A3: Dropout = 子网络集成的近似,说明为什么测试时不用Dropout但保持scaling
早期停止是什么?从头学起
早期停止 = 在验证集性能开始下降时停止训练。
训练过程中:
- 训练loss一直下降
- 验证loss先下降,然后在某个点开始上升(过拟合开始)
早期停止在验证集性能下降前把最好的模型保存下来。
为什么有效?
- 它是最简单的正则化方法
- 它限制了迭代次数=parameter空间的有效复杂度
- 它无额外参数(只有patience和监视频率)
Early Stopping策略与实战
1. Patience(耐心值)
等待多少轮没改善后停止。
- patience=5: 验证loss连续5轮不下降则停
- patience=20: 等待20轮(大模型)
- patience太小: 可能在平台区早停
- patience太大: 浪费计算资源
2. 监视指标
- 验证loss(最常用)
- 验证准确率(注意“更高更好”还是“更低更好”)
- F1 Score / AUC / BLEU…
3. Restore Best Weights
最重要的一个选项——停止后自动回滑到验证集最佳时的权重。不然最后一步的模型可能已经过拟合。
4. Delta(改善阈值)
只有验证loss下降超过某个阈值时才视为“有改善”。
例如delta=0.001,如果下降小于0.001则不计数。避免因小浮动而算“改善”。
实战经验:
- patience默认5-10。大模型可用30-50
- 早期停止与Learning Rate Decay联用效果最佳
- ReduceLROnPlateau: 验证loss平台时降学习率,再观察patience
- 如果训练loss已经很低但验证大幅上升——过拟合,应即停
Early Stopping参数对照表
| 参数 | 默认值 | 作用 | 指南 |
|---|---|---|---|
| patience | 5-10 | 等待多少轮无改善后停止 | 10个好起点 |
| min_delta | 1e-4 | 最小改善阈值 | 1e-4避免噪声影响 |
| monitor | val_loss | 监视指标 | val_loss或val_acc |
| mode | min | min/loss趋小 or max/acc趋大 | val_loss用min |
| restore_best_weights | True | 回滑最佳权重 | 建议开启 |
| start_from_epoch | 5-10 | 多少轮后开始监视 | 避免初期浮动 |
Early Stopping数值示例
简单例子:
训练一个网络的验证loss记录:
Epoch | val_loss | 是否最佳? | 等待计数 1 | 0.850 | ✓ | 0 2 | 0.720 | ✓ | 0 3 | 0.650 | ✓ | 0 4 | 0.620 | ✓ | 0 5 | 0.610 | ✓ | 0 6 | 0.615 | ✗ | 1 7 | 0.618 | ✗ | 2 8 | 0.612 | ✗ | 3 9 | 0.625 | ✗ | 4 10 | 0.640 | ✗ | 5 → STOP!
patience=5,第6轮开始验证loss不再下降,连续5轮后训练停止。最终保存的是第5轮的模型(val_loss=0.610)。
复杂例子:
一个大型模型训练ResNet-50于ImageNet,使用patience=10:
Epoch | train_loss | val_acc | 最佳 | 等待 ------|------------|----------|------|------ 1 | 1.824 | 48.2% | ✓ | 0 ... | ... | ... | ... | ... 30 | 0.315 | 74.1% | ✓ | 0 31 | 0.308 | 74.2% | ✓ | 0 32 | 0.298 | 74.4% | ✓ | 0 33 | 0.278 | 74.3% | ✗ | 1 34 | 0.265 | 74.0% | ✗ | 2 35 | 0.251 | 73.8% | ✗ | 3 36 | 0.248 | 74.0% | ✗ | 4 37 | 0.241 | 73.5% | ✗ | 5 38 | 0.239 | 73.2% | ✗ | 6 39 | 0.235 | 73.0% | ✗ | 7 40 | 0.232 | 72.5% | ✗ | 8 41 | 0.230 | 72.1% | ✗ | 9 42 | 0.228 | 71.8% | ✗ | 10 → STOP
train_loss一直下降,但val_acc在epoch32后不再上升,过拟合开始。patience=10后停止,回滑到epoch32的权重。
实战练习
Q1:你的训练中验证loss波动很大,patience=5导致训练早停。应该怎么办?
A1:(1)增大patience,如10-20;(2)加smoothed val_loss(移动平均)作为监视指标;(3)增大min_delta降低灵敏度;(4)检查batch_size是否太小导致噪声大。
Q2:你的训练过程中,验证loss下降到某点后平台,然后在patience到达前扫描到更低点。这是否意味着early stopping失败?
A2:不是!patience恢复的确会重置计数。这表示模型假性平台后又找到更好的解。patience越大,防止这种早停的能力越强。
Q3:Early Stopping和LR Reduce on Plateau有什么区别?能同时使用吗?
A3:ReduceLROnPlateau是在验证loss平台时减少学习率,而不是停止训练。两者可以完美配合:
val_loss 平台(patience=3)→ Reduce LR (×0.1) val_loss 再平台(patience=5)→ Reduce LR 再×0.1 val_loss 仍平台(patience=10)→ Early Stop
查看答案
A1: 增大patience到20,或用movng avg val_loss监视
A2: 不是失败。Patience重置是正常的,说明模型继续学习
A3: 可以同时使用。先Reduce LR再Early Stop
梯度裁剪 (Gradient Clipping)
梯度裁剪 = 当梯度太大时“截断”它,防止梯度爆炸。
在深层网络或RNN/LSTM中,梯度有可能变得极大,导致权重更新飞快,loss变NaN。
两种方法:
- Value Clipping:单个梯度值被截断到[max_grad, max_grad]范围
- Norm Clipping:所有梯度的范数被截断到max_norm以下
Norm Clipping公式:
||g|| ≤ max_norm: g' = g ||g|| > max_norm: g' = g × (max_norm / ||g||)
保持梯度方向不变,但缩放其大小。
常见参数:
- max_norm=1.0: 严格裁剪
- max_norm=5.0: 常见默认
- max_norm=10.0: 宽松裁剪
常用场景:
- RNN/LSTM: 更时间步梯度累乘容易爆炸
- Transformer: 大型模型训练时保险
- GAN: 生成器和辨别器的竞争训练不稳定
- RL: PPO等策略梯度可能很大
训练技巧一览表
| 技巧 | 解决问题 | 关键参数 | 黄金规则 | 备注 |
|---|---|---|---|---|
| 学习率 | 收敛慢/发散 | α, Warmup, Decay | Adam=0.001, SGD+Cosine | 最重要超参 |
| Batch Size | 速度/稳定性 | batch_size | 32/64/128 | 大batch需加正则 |
| L2 Regularization | 过拟合 | λ | 1e-4(神经网络) | 最常用正则化 |
| L1 Regularization | 特征选择 | λ | 0.001-0.01 | 稀疏解 |
| Dropout | 过拟合 | p | hidden=0.5, input=0.2 | CNN少用 |
| Early Stopping | 过拟合 | patience, delta | patience=10 | 最简单正则化 |
| 梯度裁剪 | 梯度爆炸 | max_norm | RNN=5.0, Transformer=1.0 | RNN必用 |
实战总结:训练流程检查清单
训练一个新模型时,建议按以下顺序调参:
- 确保数据正确——先过拟合一小批数据(如16个)确保loss能降到0
- 设置学习率——Adam α=0.001, SGD+Momentum α=0.01起步
- 选Batch Size——显卡内存允许的最大值,建议32-256
- 加正则化——L2 weight_decay=1e-4开始
- 加Dropout——如果过拟合严重
- 设Early Stopping——patience=10
- 加梯度裁剪——RNN/语言模型必用
- 使用Warmup + Cosine Decay——对大模型差不多是必须的
常见问题诊断指南:
- Loss NaN:学习率太大 / 梯度爆炸 → 降学习率 + gradient clipping
- Loss不下降:学习率太小 / 数据没标准化 / 激活函数不对 → 检查数据/模型
- Train高但Validation低:过拟合 → 增强正则化 / 多数据 / 小模型
- Train低但Validation也低:正则化太强 / 数据问题 / 模型不足 → 减弱正则化 / 增加模型大小
PyTorch实现示例:
# AdamW + Cosine Decay + Warmup + Early Stopping + Gradient Clipping
import torch, torch.optim as optim
from torch.optim.lr_scheduler import CosineAnnealingLR
model = MyModel()
optimizer = optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4)
scheduler = CosineAnnealingLR(optimizer, T_max=100)
best_val_loss = float('inf')
patience_counter = 0
patience = 10
for epoch in range(200):
train_loss = train_one_epoch(model, optimizer, dataloader)
# Gradient Clipping
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=5.0)
val_loss = evaluate(model, val_loader)
scheduler.step()
# Early Stopping
if val_loss < best_val_loss:
best_val_loss = val_loss
torch.save(model.state_dict(), 'best_model.pth')
patience_counter = 0
else:
patience_counter += 1
if patience_counter >= patience:
print(f'Early stop at epoch {epoch}')
break