Skip to content
🔗 分享本题
查看我的学习进度 →

Transformer 训练工具箱动漫知识图:Warmup、Label Smoothing、Dropout、梯度裁剪、混合精度、梯度累积和分布式并行分别改善稳定性、泛化、显存与吞吐

🧠 图解记忆:先稳优化,再控过拟合,最后扩吞吐;点击图片可查看原图。

💡 答案要点

核心优化方向:

  1. 学习率调度
  2. 正则化
  3. 训练稳定性
  4. 计算效率

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.2

3. 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.1

4. 梯度裁剪(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_model512
n_heads8
d_ff2048
n_layers6
dropout0.1
warmup_steps4000
label_smoothing0.1
max_grad_norm1.0
batch_size25K tokens
optimizerAdam(β1=0.9, β2=0.98, ε=1e-9)

面试话术:

"Transformer 训练的关键优化包括:Warmup学习率调度(先升后降)、Label Smoothing防过拟合、多层Dropout正则化、梯度裁剪防爆炸。工程上用混合精度训练加速2-3倍,梯度累积模拟大batch。"