🧠 图解记忆:先稳优化,再控过拟合,最后扩吞吐;点击图片可查看原图。
💡 答案要点
核心优化方向:
- 学习率调度
- 正则化
- 训练稳定性
- 计算效率
1. 学习率调度(Warmup + Decay):
python
# Warmup阶段:线性增加学习率
def get_lr(step, d_model, warmup_steps=4000):
# Transformer 原论文方案
lr = d_model ** (-0.5) * min(
step ** (-0.5),
step * warmup_steps ** (-1.5)
)
return lr
# 为什么需要Warmup?
# - 初始时权重随机,梯度不稳定
# - 小学习率让模型"热身"
# - 然后逐渐增大到峰值
# - 最后逐渐衰减
# 典型曲线:
# 0-4K步:线性增加 0 → peak_lr
# 4K步后:按 1/√step 衰减2. Label Smoothing(标签平滑):
展开 Python 代码示例(30 行)
python
# 问题:Hard Label容易过拟合
hard_label = [0, 0, 0, 1, 0] # one-hot
# 解决:Label Smoothing
smooth_label = [0.02, 0.02, 0.02, 0.92, 0.02]
# 真实类别:0.92(1 - smoothing)
# 其他类别:0.02(smoothing / (n_classes - 1))
class LabelSmoothingLoss(nn.Module):
def __init__(self, n_classes, smoothing=0.1):
super().__init__()
self.smoothing = smoothing
self.n_classes = n_classes
def forward(self, pred, target):
# pred: (batch, n_classes)
# target: (batch,) 类别索引
confidence = 1.0 - self.smoothing
smooth_value = self.smoothing / (self.n_classes - 1)
# 构造smooth label
smooth_label = torch.full_like(pred, smooth_value)
smooth_label.scatter_(1, target.unsqueeze(1), confidence)
# KL散度损失
loss = -torch.sum(smooth_label * torch.log_softmax(pred, dim=1), dim=1)
return loss.mean()
# 效果:提升泛化能力,BLEU +0.23. Dropout 策略:
python
class TransformerLayer(nn.Module):
def __init__(self, d_model=512, dropout=0.1):
super().__init__()
self.dropout = dropout
def forward(self, x):
# 1. Attention Dropout
attn_output = self.attention(x)
attn_output = F.dropout(attn_output, p=self.dropout, training=self.training)
# 2. Residual Dropout
x = x + attn_output
# 3. FFN Dropout
ffn_output = self.ffn(x)
ffn_output = F.dropout(ffn_output, p=self.dropout, training=self.training)
x = x + ffn_output
return x
# 典型配置:
# Attention Dropout: 0.1
# Residual Dropout: 0.1
# FFN Dropout: 0.1
# Embedding Dropout: 0.14. 梯度裁剪(Gradient Clipping):
python
# 防止梯度爆炸
max_grad_norm = 1.0
for batch in dataloader:
loss = model(batch)
loss.backward()
# 裁剪梯度
torch.nn.utils.clip_grad_norm_(
model.parameters(),
max_grad_norm
)
optimizer.step()
optimizer.zero_grad()5. Mixed Precision Training(混合精度):
python
from torch.cuda.amp import autocast, GradScaler
scaler = GradScaler()
for batch in dataloader:
optimizer.zero_grad()
# FP16 前向传播
with autocast():
loss = model(batch)
# 缩放损失,FP16 反向传播
scaler.scale(loss).backward()
# 更新权重(FP32)
scaler.step(optimizer)
scaler.update()
# 优势:
# - 速度提升 2-3 倍
# - 显存节省 50%
# - 精度损失 < 0.1%6. 批量大小优化:
python
# 问题:GPU显存有限,batch_size受限
# 解决:梯度累积
accumulation_steps = 4
effective_batch_size = batch_size * accumulation_steps
optimizer.zero_grad()
for i, batch in enumerate(dataloader):
loss = model(batch) / accumulation_steps
loss.backward()
if (i + 1) % accumulation_steps == 0:
optimizer.step()
optimizer.zero_grad()
# 效果:
# 原来:batch_size=32,每步更新
# 现在:batch_size=32×4=128,每4步更新
# 显存不变,效果更好7. 并行训练:
python
# 数据并行(Data Parallel)
model = nn.DataParallel(model)
# 分布式数据并行(Distributed Data Parallel,推荐)
model = nn.parallel.DistributedDataParallel(model)
# 模型并行(Model Parallel,超大模型)
# 不同层放在不同GPU
class ModelParallel(nn.Module):
def __init__(self):
super().__init__()
self.encoder = nn.Sequential(*layers[:6]).to('cuda:0')
self.decoder = nn.Sequential(*layers[6:]).to('cuda:1')
def forward(self, x):
x = self.encoder(x.to('cuda:0'))
x = self.decoder(x.to('cuda:1'))
return x典型配置(Transformer Base):
| 参数 | 值 |
|---|---|
| d_model | 512 |
| n_heads | 8 |
| d_ff | 2048 |
| n_layers | 6 |
| dropout | 0.1 |
| warmup_steps | 4000 |
| label_smoothing | 0.1 |
| max_grad_norm | 1.0 |
| batch_size | 25K tokens |
| optimizer | Adam(β1=0.9, β2=0.98, ε=1e-9) |
面试话术:
"Transformer 训练的关键优化包括:Warmup学习率调度(先升后降)、Label Smoothing防过拟合、多层Dropout正则化、梯度裁剪防爆炸。工程上用混合精度训练加速2-3倍,梯度累积模拟大batch。"
