Day 25:深度学习训练技巧全攻略
今日目标:掌握学习率调度、优化器选型、混合精度训练、梯度累积等实战技巧,让模型训练又快又稳
预计阅读:10分钟 | 动手操作:40分钟
一、训练技巧全景图
┌──────────────────────────────────────────────────┐
│ 深度学习训练加速工具箱 │
├──────────────┬──────────────┬────────────────────┤
│ 学习率调度 │ 优化器选型 │ 精度与内存 │
│ Step/Cosine │ SGD/Adam/ │ 混合精度/梯度累积 │
│ Warmup/ │ AdamW/ │ 梯度裁剪/ │
│ OneCycle │ RMSprop │ 梯度检查点 │
├──────────────┼──────────────┼────────────────────┤
│ 初始化 │ 分布式训练 │ 调试诊断 │
│ Kaiming/ │ DataParallel/│ loss曲线/NAN排查/ │
│ Xavier/ │ DDP/FSDP │ 过拟合欠拟合 │
│ 正交初始化 │ │ │
└──────────────┴──────────────┴────────────────────┘
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.optim.lr_scheduler import (
StepLR, CosineAnnealingLR, CosineAnnealingWarmRestarts,
OneCycleLR, ReduceLROnPlateau, LambdaLR
)
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
from torch.cuda.amp import autocast, GradScaler
import numpy as np
torch.manual_seed(42)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
二、核心知识点
2.1 学习率调度:训练的"油门"
"""
学习率是训练中最重要(也是最难调)的超参数
太大了 → 不收敛,loss震荡
太小了 → 收敛太慢,陷入局部最优
刚刚好 → 快速稳定收敛
学习率调度 = 训练过程中动态调整学习率
"""
# 准备数据
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2470, 0.2435, 0.2616)),
])
train_dataset = datasets.CIFAR10('./data', train=True, download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=128, shuffle=True, num_workers=0)
def create_model():
"""快速创建一个简单CNN用于演示"""
return nn.Sequential(
nn.Conv2d(3, 32, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
nn.Conv2d(64, 128, 3, padding=1), nn.ReLU(), nn.AdaptiveAvgPool2d(1),
nn.Flatten(), nn.Linear(128, 10),
)
def compare_lr_schedulers():
"""对比不同学习率调度策略"""
schedulers = {
'StepLR (gamma=0.5, step=30)': lambda opt: StepLR(opt, step_size=30, gamma=0.5),
'CosineAnnealing': lambda opt: CosineAnnealingLR(opt, T_max=50, eta_min=1e-5),
'CosineWarmRestarts': lambda opt: CosineAnnealingWarmRestarts(opt, T_0=20, T_mult=2),
'OneCycleLR': lambda opt: OneCycleLR(opt, max_lr=0.01, steps_per_epoch=len(train_loader), epochs=50),
'ReduceLROnPlateau': lambda opt: ReduceLROnPlateau(opt, mode='min', factor=0.5, patience=5),
'No Scheduler': lambda opt: None,
}
# 模拟训练过程,记录学习率变化
print("学习率变化对比 (前50个epoch):")
print(f"{'Scheduler':<25s} {'初始LR':>10s} {'最终LR':>10s} {'变化曲线':>20s}")
print('-' * 70)
for name, scheduler_fn in schedulers.items():
model = create_model()
optimizer = optim.SGD(model.parameters(), lr=0.01)
scheduler = scheduler_fn(optimizer)
lr_history = []
for epoch in range(50):
# 模拟训练
for batch_idx, (x, y) in enumerate(train_loader):
if batch_idx > 0: # 只模拟1个batch
break
optimizer.zero_grad()
loss = F.cross_entropy(model(x), y)
loss.backward()
optimizer.step()
if scheduler is not None:
if isinstance(scheduler, ReduceLROnPlateau):
scheduler.step(loss.item())
else:
scheduler.step()
lr_history.append(optimizer.param_groups[0]['lr'])
curve = '↘' + '─' * int(lr_history[-1] / lr_history[0] * 10)
print(f"{name:<25s} {lr_history[0]:>10.6f} {lr_history[-1]:>10.6f} {curve:<20s}")
compare_lr_schedulers()
学习率 Warmup
def warmup_lambda(epoch, warmup_epochs=5):
"""学习率warmup:前N个epoch从0线性增长到初始lr"""
if epoch < warmup_epochs:
return (epoch + 1) / warmup_epochs
return 1.0
# 使用
# scheduler = LambdaLR(optimizer, lr_lambda=lambda e: warmup_lambda(e, 5))
"""
Warmup为什么重要:
1. 训练初期模型参数是随机的,梯度方向不稳定
2. 大学习率会让模型"跑偏",难以纠正
3. Warmup让模型先用小学习率找到正确方向,再加速
经验:warmup 5个epoch对大多数任务都有效
"""
学习率调度器选型指南
"""
学习率调度器选型指南:
┌──────────────────────┬────────────────────┬──────────────────────┐
│ 调度器 │ 适用场景 │ 特点 │
├──────────────────────┼────────────────────┼──────────────────────┤
│ StepLR │ 传统CNN任务 │ 简单粗暴,阶梯下降 │
│ CosineAnnealing │ 大多数任务(推荐) │ 平滑下降,当前主流 │
│ CosineWarmRestarts │ 长时间训练 │ 周期性重启,跳出局部 │
│ OneCycleLR │ 快速训练 │ 先升后降,收敛快 │
│ ReduceLROnPlateau │ 自动调参 │ loss不降时自动降lr │
│ LambdaLR │ 自定义策略 │ 完全灵活 │
└──────────────────────┴────────────────────┴──────────────────────┘
推荐默认方案:
一般任务: CosineAnnealingLR(optimizer, T_max=epochs)
需要调参: ReduceLROnPlateau(optimizer, patience=5)
追求极致: CosineAnnealing + Warmup
"""
2.2 优化器选型:SGD、Adam、AdamW
"""
优化器选型指南:
┌──────────┬──────────────┬──────────────┬──────────────────────┐
│ 优化器 │ 特点 │ 适用场景 │ 端侧AI建议 │
├──────────┼──────────────┼──────────────┼──────────────────────┤
│ SGD+M │ 需要调参, │ 目标检测/ │ 检测模型首选, │
│ │ 泛化性好 │ 图像分类 │ 泛化能力更强 │
│ Adam │ 自适应, │ NLP/快速原型 │ 不推荐,没有weight │
│ │ 收敛快 │ │ decay的解耦 │
│ AdamW │ 解耦weight │ 通用(推荐) │ 推荐!分类任务首选 │
│ │ decay │ │ │
│ RMSprop │ 处理非平稳 │ RNN/强化学习 │ 端侧AI不常用 │
└──────────┴──────────────┴──────────────┴──────────────────────┘
选型口诀:
- 分类任务 → AdamW (lr=1e-3, weight_decay=1e-4)
- 检测任务 → SGD + Momentum (lr=1e-2, momentum=0.9)
- 不确定 → AdamW,大概率不会错
"""
def compare_optimizers():
"""对比不同优化器的收敛速度"""
optimizers = {
'SGD': lambda params: optim.SGD(params, lr=0.01),
'SGD+Momentum': lambda params: optim.SGD(params, lr=0.01, momentum=0.9),
'Adam': lambda params: optim.Adam(params, lr=0.001),
'AdamW': lambda params: optim.AdamW(params, lr=0.001, weight_decay=1e-4),
}
print("\n优化器收敛对比 (5个epoch):")
print(f"{'优化器':<15s} {'初始Loss':>10s} {'最终Loss':>10s} {'下降':>10s}")
print('-' * 50)
for name, opt_fn in optimizers.items():
model = create_model()
optimizer = opt_fn(model.parameters())
losses = []
for epoch in range(5):
for x, y in train_loader:
optimizer.zero_grad()
loss = F.cross_entropy(model(x), y)
loss.backward()
optimizer.step()
losses.append(loss.item())
if len(losses) > 50: # 只模拟少量steps
break
print(f"{name:<15s} {losses[0]:>10.4f} {losses[-1]:>10.4f} {losses[0]-losses[-1]:>10.4f}")
compare_optimizers()
2.3 混合精度训练(AMP):白嫖显存和速度
"""
混合精度训练 = float32 + float16 混合使用
为什么:
- float16计算速度是float32的2-4倍(取决于GPU架构)
- float16显存占用减半
- 大多数操作float16精度足够
怎么做:
- 前向传播用float16(快)
- 反向传播时敏感操作(softmax, loss)用float32(稳)
- 用GradScaler防止梯度下溢
PyTorch AMP只需加3行代码!
"""
def train_with_amp(model, loader, epochs=5):
"""使用混合精度训练"""
model = model.to(device)
optimizer = optim.AdamW(model.parameters(), lr=0.001)
criterion = nn.CrossEntropyLoss()
scaler = GradScaler() # 1. 创建GradScaler
for epoch in range(epochs):
model.train()
for x, y in loader:
x, y = x.to(device), y.to(device)
optimizer.zero_grad()
# 2. autocast上下文
with autocast():
output = model(x)
loss = criterion(output, y)
# 3. scaler处理梯度
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
if epoch == 0:
break
print("AMP训练演示完成!")
def compare_amp_performance():
"""对比AMP和FP32的速度和显存"""
model = create_model().to(device)
dummy_input = torch.randn(64, 3, 32, 32).to(device)
# 预热
for _ in range(10):
_ = model(dummy_input)
# FP32
import time
torch.cuda.synchronize()
start = time.time()
for _ in range(100):
_ = model(dummy_input)
torch.cuda.synchronize()
fp32_time = time.time() - start
# AMP
torch.cuda.synchronize()
start = time.time()
for _ in range(100):
with autocast():
_ = model(dummy_input)
torch.cuda.synchronize()
amp_time = time.time() - start
print(f"\n混合精度性能对比:")
print(f" FP32: {fp32_time:.3f}s ({100/fp32_time:.0f} iters/s)")
print(f" AMP: {amp_time:.3f}s ({100/amp_time:.0f} iters/s)")
print(f" 加速: {fp32_time/amp_time:.1f}x")
if torch.cuda.is_available():
print(f"\n 显存占用 (估算):")
mem = torch.cuda.memory_allocated() / 1024**2
print(f" FP32权重: {sum(p.numel()*4 for p in model.parameters())/1024**2:.1f} MB")
print(f" FP16权重: {sum(p.numel()*2 for p in model.parameters())/1024**2:.1f} MB (理论上)")
print(f" 实际节省: 约40-50%显存")
if torch.cuda.is_available():
compare_amp_performance()
2.4 梯度累积:小显存也能用大Batch
"""
梯度累积 = 多个小batch的梯度累加,再一次性更新
场景:你只有8GB显存,想用batch_size=256
方案:batch_size=32 + gradient_accumulation_steps=8
效果:loss曲线和真正的batch_size=256几乎一样!
"""
def train_with_gradient_accumulation(model, loader, accumulation_steps=4):
"""
梯度累积训练
accumulation_steps=4 意味着:
每4个batch累加梯度,然后更新一次
等价于 batch_size 扩大了4倍
"""
model = model.to(device)
optimizer = optim.AdamW(model.parameters(), lr=0.001)
criterion = nn.CrossEntropyLoss()
model.train()
for batch_idx, (x, y) in enumerate(loader):
if batch_idx >= 20: # 只演示
break
x, y = x.to(device), y.to(device)
# 前向传播
output = model(x)
loss = criterion(output, y) / accumulation_steps # 注意:loss要除以累积步数!
loss.backward()
# 每 accumulation_steps 步更新一次
if (batch_idx + 1) % accumulation_steps == 0:
optimizer.step()
optimizer.zero_grad()
print("梯度累积演示完成!")
def gradient_accumulation_example():
"""
梯度累积等效性证明
正常batch_size=128:
loss = sum(loss_i) / 128
loss.backward()
optimizer.step()
梯度累积 batch_size=32, steps=4:
for i in range(4):
loss = sum(loss_i) / 32
(loss / 4).backward() # 除以4保持梯度尺度一致
optimizer.step()
两种方式等价的数学证明:
∂/∂θ (1/128 * ΣL_i) = 1/128 * Σ(∂L_i/∂θ)
= 1/4 * [1/32 * Σ_1(∂L_i/∂θ)] + 1/4 * [1/32 * Σ_2(∂L_i/∂θ)] + ... ✓
"""
print("梯度累积等效性: 已验证 ✓")
print("关键:每次backward前loss要除以accumulation_steps!")
gradient_accumulation_example()
2.5 梯度裁剪:防止梯度爆炸
"""
梯度裁剪:当梯度的L2范数超过阈值时,按比例缩小
使用场景:
- RNN/LSTM/Transformer训练(序列长,梯度容易爆炸)
- 训练不稳定时
- 使用大学习率时
Pytorch一行代码:
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
"""
def gradient_clipping_demo():
"""演示梯度裁剪的效果"""
model = create_model()
# 制造一个会产生大梯度的情况
x = torch.randn(1, 3, 32, 32) * 100 # 异常大的输入
# 不裁剪
output = model(x)
loss = output.sum()
loss.backward()
grad_norms_no_clip = []
for p in model.parameters():
if p.grad is not None:
grad_norms_no_clip.append(p.grad.norm().item())
# 裁剪
model.zero_grad()
output = model(x)
loss = output.sum()
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
grad_norms_clipped = []
for p in model.parameters():
if p.grad is not None:
grad_norms_clipped.append(p.grad.norm().item())
print("梯度裁剪效果:")
print(f" 不裁剪 - 最大梯度范数: {max(grad_norms_no_clip):.4f}")
print(f" 裁剪后 - 最大梯度范数: {max(grad_norms_clipped):.4f}")
print(f" 裁剪比例: {max(grad_norms_clipped)/max(grad_norms_no_clip)*100:.1f}%")
gradient_clipping_demo()
2.6 权重初始化
def demonstrate_weight_init():
"""演示不同初始化方法"""
x = torch.randn(100, 256)
print("权重初始化方法对比:")
# 1. 全零初始化 → 所有神经元学一样的东西 → 对称性问题
w_zeros = nn.Linear(256, 128)
nn.init.zeros_(w_zeros.weight)
out_zeros = w_zeros(x)
print(f" 全零: 输出均值={out_zeros.mean():.4f}, 标准差={out_zeros.std():.4f} → 没用!")
# 2. 标准正态初始化 → 深层网络容易梯度消失/爆炸
w_normal = nn.Linear(256, 128)
nn.init.normal_(w_normal.weight, mean=0, std=0.01)
out_normal = w_normal(x)
print(f" 正态(0,0.01): 输出均值={out_normal.mean():.4f}, 标准差={out_normal.std():.4f}")
# 3. Xavier初始化(适合tanh/sigmoid)
w_xavier = nn.Linear(256, 128)
nn.init.xavier_normal_(w_xavier.weight)
out_xavier = w_xavier(x)
print(f" Xavier: 输出均值={out_xavier.mean():.4f}, 标准差={out_xavier.std():.4f} → 方差保持")
# 4. Kaiming初始化(适合ReLU,最常用!)
w_kaiming = nn.Linear(256, 128)
nn.init.kaiming_normal_(w_kaiming.weight, mode='fan_in', nonlinearity='relu')
out_kaiming = w_kaiming(x)
print(f" Kaiming: 输出均值={out_kaiming.mean():.4f}, 标准差={out_kaiming.std():.4f} → 推荐!")
print("\n PyTorch默认的Linear用的就是Kaiming初始化!")
demonstrate_weight_init()
三、动手实践:完整的训练技巧集成
3.1 实战:把所有技巧整合到一个训练脚本
class TrainingPipeline:
"""
集成所有训练技巧的训练Pipeline
包含:
✅ 学习率Warmup + CosineAnnealing
✅ AdamW优化器
✅ 混合精度训练 (AMP)
✅ 梯度累积(可选)
✅ 梯度裁剪
✅ 早停
"""
def __init__(self, model, device,
lr=0.001, weight_decay=1e-4,
warmup_epochs=5, total_epochs=100,
use_amp=True, accumulation_steps=1,
grad_clip=1.0, patience=10):
self.model = model.to(device)
self.device = device
self.use_amp = use_amp
self.accumulation_steps = accumulation_steps
self.grad_clip = grad_clip
self.patience = patience
# 优化器
self.optimizer = optim.AdamW(model.parameters(), lr=lr, weight_decay=weight_decay)
# 学习率调度:Warmup + Cosine
def lr_lambda(epoch):
if epoch < warmup_epochs:
return (epoch + 1) / warmup_epochs # Warmup
# Cosine annealing
progress = (epoch - warmup_epochs) / (total_epochs - warmup_epochs)
return 0.5 * (1 + np.cos(np.pi * progress))
self.scheduler = LambdaLR(self.optimizer, lr_lambda)
self.criterion = nn.CrossEntropyLoss()
self.scaler = GradScaler() if use_amp else None
# 训练状态
self.best_acc = 0
self.best_epoch = 0
self.epochs_no_improve = 0
def train_epoch(self, loader):
self.model.train()
total_loss, correct, total = 0, 0, 0
for batch_idx, (x, y) in enumerate(loader):
x, y = x.to(self.device), y.to(self.device)
# 混合精度
if self.use_amp:
with autocast():
output = self.model(x)
loss = self.criterion(output, y) / self.accumulation_steps
self.scaler.scale(loss).backward()
if (batch_idx + 1) % self.accumulation_steps == 0:
# 梯度裁剪
self.scaler.unscale_(self.optimizer)
torch.nn.utils.clip_grad_norm_(self.model.parameters(), self.grad_clip)
self.scaler.step(self.optimizer)
self.scaler.update()
self.optimizer.zero_grad()
else:
output = self.model(x)
loss = self.criterion(output, y) / self.accumulation_steps
loss.backward()
if (batch_idx + 1) % self.accumulation_steps == 0:
torch.nn.utils.clip_grad_norm_(self.model.parameters(), self.grad_clip)
self.optimizer.step()
self.optimizer.zero_grad()
with torch.no_grad():
total_loss += loss.item() * self.accumulation_steps * x.size(0)
pred = output.argmax(1)
correct += pred.eq(y).sum().item()
total += y.size(0)
return total_loss / total, correct / total
@torch.no_grad()
def evaluate(self, loader):
self.model.eval()
total_loss, correct, total = 0, 0, 0
for x, y in loader:
x, y = x.to(self.device), y.to(self.device)
if self.use_amp:
with autocast():
output = self.model(x)
loss = self.criterion(output, y)
else:
output = self.model(x)
loss = self.criterion(output, y)
total_loss += loss.item() * x.size(0)
correct += output.argmax(1).eq(y).sum().item()
total += y.size(0)
return total_loss / total, correct / total
def fit(self, train_loader, val_loader, epochs):
for epoch in range(epochs):
train_loss, train_acc = self.train_epoch(train_loader)
val_loss, val_acc = self.evaluate(val_loader)
self.scheduler.step()
# 保存最佳模型
if val_acc > self.best_acc:
self.best_acc = val_acc
self.best_epoch = epoch + 1
self.epochs_no_improve = 0
torch.save(self.model.state_dict(), 'best_model.pth')
else:
self.epochs_no_improve += 1
if epoch % 10 == 0:
lr = self.optimizer.param_groups[0]['lr']
print(f"Epoch {epoch+1:3d}: "
f"Train {train_acc:.2%}, Val {val_acc:.2%}, "
f"LR {lr:.6f}, Best {self.best_acc:.2%}")
# 早停
if self.epochs_no_improve >= self.patience:
print(f"早停!第 {epoch+1} 个epoch停止")
break
print(f"\n训练完成!最佳val_acc={self.best_acc:.2%} (epoch {self.best_epoch})")
self.model.load_state_dict(torch.load('best_model.pth'))
return self.model
# 使用
# model = create_model()
# pipeline = TrainingPipeline(model, device, lr=0.001, total_epochs=50)
# pipeline.fit(train_loader, val_loader, epochs=50)
四、训练诊断:Loss不下降怎么办?
"""
训练出问题时的诊断流程:
1. loss不下降:
→ 检查学习率是否太大或太小 → 从1e-3开始探索
→ 检查数据加载是否正确 → 打印一个batch看看
→ 检查模型是否在训练模式 → model.train()
→ 检查梯度是否为零 → 打印param.grad
2. loss变成NaN:
→ 学习率太大 → 降10倍
→ 数据中有NaN → 检查数据预处理
→ 梯度爆炸 → 加梯度裁剪
→ 除零错误 → 检查自定义loss中的除法
3. 训练集准确率很高,验证集很低:
→ 过拟合 → 加正则化/数据增强/减少模型容量
4. 训练集和验证集准确率都很低:
→ 欠拟合 → 加模型容量/降学习率/增加训练时间
5. loss震荡:
→ 学习率太大 → 降10倍
→ batch_size太小 → 增大batch_size或加梯度累积
诊断口诀:
不收敛 → 降学习率
NaN → 降学习率 + 梯度裁剪
过拟合 → 加正则化
欠拟合 → 加模型/训练时间
"""
五、常见坑点
坑1:AMP中loss.backward()之前不要手动除
# ❌ 错误:自己除了loss,scaler又scale了一次
loss = criterion(output, y) / accumulation_steps
scaler.scale(loss).backward() # 双重缩放!
# ✅ 正确:accumulation时用scaler
loss = criterion(output, y)
scaler.scale(loss / accumulation_steps).backward()
坑2:ReduceLROnPlateau需要手动传loss
# scheduler = ReduceLROnPlateau(optimizer, patience=5)
# scheduler.step(val_loss) # 必须传入验证loss,不是训练loss!
坑3:AdamW的weight_decay和L2正则化不同
# AdamW解耦了weight_decay和L2正则化
# SGD: θ = θ - lr * (∇L + 2*λ*θ)
# AdamW: θ = θ - lr * ∇L - lr * λ * θ
# 效果:AdamW的weight_decay等价于L2,但Adam的不等价
# 所以:用AdamW,别用Adam + weight_decay
坑4:梯度累积时BatchNorm的处理
# BN在每次forward时更新running_mean/running_var
# 梯度累积时,多个小batch的BN统计量不同
# 影响:accumulation_steps太大时,BN统计量不准确
# 解决方案:
# 1. accumulation_steps不要太大(≤4一般没问题)
# 2. 用SyncBatchNorm(多卡时)
# 3. 用GroupNorm代替BatchNorm(不依赖batch统计量)
六、今日作业
- 学习率实验:对比StepLR和CosineAnnealing,记录训练曲线差异
- AMP实验:对比FP32和AMP的训练速度和显存占用
- 梯度累积:用batch_size=32 + accumulation_steps=4模拟batch_size=128,验证loss曲线一致性
- 打卡:评论区发你的实验结果,格式:“Day 25/100 打卡:训练技巧全部掌握!”
今日小结
今天你学会了:
✅ 6种学习率调度器及选型指南
✅ SGD/Adam/AdamW优化器选型
✅ 混合精度训练(AMP)—— 3行代码加速2-4x
✅ 梯度累积 —— 小显存也能用大Batch
✅ 梯度裁剪 —— 防止梯度爆炸
✅ 4种权重初始化方法
✅ 集成所有技巧的完整TrainingPipeline
✅ 训练诊断流程(loss不下降/NaN/过拟合/欠拟合)
✅ 4个经典坑点
明日预告
Day 26:数据增强技术 — 让模型更鲁棒
几何变换、颜色变换、CutOut、MixUp、CutMix、AutoAugment
🔥 关注我,每天解锁一个端侧AI技能!
微信公众号:xxx | 小红书:xxx | CSDN:xxx
评论区打卡,一起坚持100天!
附:小红书图文版
封面标题建议:模型训练加速大全 | 这些技巧让训练飞起来 🚀
P1 — 封面
标题:训练技巧全攻略
副标题:学习率 / 优化器 / AMP / 梯度累积
关键词:训练技巧 / 加速 / 深度学习
P2 — 学习率调度
6种调度器选型指南
推荐:CosineAnnealing + Warmup
StepLR简单粗暴,Cosine平滑下降
OneCycle收敛最快
P3 — 优化器选型
分类→AdamW (lr=1e-3)
检测→SGD+Momentum (lr=1e-2)
不确定→AdamW,大概率不会错
AdamW > Adam(解耦weight_decay)
P4 — 混合精度AMP
只用3行代码,加速2-4倍
显存节省40-50%
autocast + GradScaler
端侧AI训练省显存的利器
P5 — 梯度累积+裁剪
梯度累积:小显存用大Batch
batch_size=32×4步=128效果
梯度裁剪:防止梯度爆炸
max_norm=1.0是常用值
P6 — 今日作业
学习率对比实验 + AMP实验
评论区打卡 Day 25/100
标签:#训练技巧 #学习率 #混合精度 #深度学习
CSDN发布提示:CSDN版本建议在学习率调度部分放6张学习率变化曲线图,在AMP部分放速度对比柱状图,在Pipeline部分放流程图。
更多推荐


所有评论(0)