返回学习地图
llmPhase A · 第 6

05. 训练技巧

学习率/Batch/正则化/Dropout/早期停止:让模型训练又快又稳的实用技术

29 个章节·按类别展开/折叠
知识

为什么训练需要技巧?

上一章我们学习了损失函数——它告诉模型“你错了多少”。但知道错了多少和能够正确地把错误改正过来,是两回事。

训练一个神经网络就像炖牛肉——火候太大会烧焦(发散),火候太小炖不烂(收敛慢),调料不对味道奇怪(过拟合)。本章就是“炖牛肉宝典”。

具体来说,我们将学习:

  • 学习率:步长大小如何调整?热身(温炉) · 阶梯衰减 · 余弦衰减
  • 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初期方差估计不稳
表格

学习率策略参数对照表

策略关键参数适用场景备注
固定学习率α简单小模型不建议大模型
WarmupT_warmup, α_targetTransformer/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.00001

Q3: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-16GAN/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²权重越大罚款越重❌ 不为00.0001~0.01神经网络默认
L1 (Lasso)∑|w|绝对值罚款✅ 为00.0001~0.01特征选择/稀疏模型
Elastic Netr·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适用层特点适用场景
标准Dropout0.5全连接隐藏层最简单常用MLP/FC网络
输入Dropout0.2-0.3输入层保护输入特征噪声数据
空间Dropout0.2-0.5CNN卷积层整通道置零CNN
AlphaDropout0.05-0.1SELU激活层保持均值方差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参数对照表

参数默认值作用指南
patience5-10等待多少轮无改善后停止10个好起点
min_delta1e-4最小改善阈值1e-4避免噪声影响
monitorval_loss监视指标val_loss或val_acc
modeminmin/loss趋小 or max/acc趋大val_loss用min
restore_best_weightsTrue回滑最佳权重建议开启
start_from_epoch5-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, DecayAdam=0.001, SGD+Cosine最重要超参
Batch Size速度/稳定性batch_size32/64/128大batch需加正则
L2 Regularization过拟合λ1e-4(神经网络)最常用正则化
L1 Regularization特征选择λ0.001-0.01稀疏解
Dropout过拟合phidden=0.5, input=0.2CNN少用
Early Stopping过拟合patience, deltapatience=10最简单正则化
梯度裁剪梯度爆炸max_normRNN=5.0, Transformer=1.0RNN必用
知识

实战总结:训练流程检查清单

训练一个新模型时,建议按以下顺序调参:

  1. 确保数据正确——先过拟合一小批数据(如16个)确保loss能降到0
  2. 设置学习率——Adam α=0.001, SGD+Momentum α=0.01起步
  3. 选Batch Size——显卡内存允许的最大值,建议32-256
  4. 加正则化——L2 weight_decay=1e-4开始
  5. 加Dropout——如果过拟合严重
  6. 设Early Stopping——patience=10
  7. 加梯度裁剪——RNN/语言模型必用
  8. 使用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