共计 2299 个字符,预计需要花费 6 分钟才能阅读完成。
环境准备
- CUDA/cuDNN 版本选择
- 1080ti 基于 Pascal 架构,最高支持 CUDA 11.6(需驱动版本≥465.19.01)
- 推荐组合:CUDA 11.3 + cuDNN 8.2.1,经测试在 PyTorch 1.12 下稳定性最佳
-
验证命令:
nvcc --version # 查看 CUDA 编译器版本 cat /usr/local/cuda/version.txt # 查看运行时版本
-
框架安装注意事项
- PyTorch 安装需明确指定 CUDA 版本:
pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 \ --extra-index-url https://download.pytorch.org/whl/cu113 - TensorFlow 2.10+ 需禁用 GPU 自动内存增长:
gpus = tf.config.experimental.list_physical_devices('GPU') tf.config.experimental.set_memory_growth(gpus[0], True)
显存优化技术
- 梯度检查点(Gradient Checkpointing)
- 原理:用计算时间换显存,仅保存部分节点的中间结果,反向传播时重新计算
- 数学代价:额外增加约 30% 前向计算量,减少 50-70% 显存占用
-
PyTorch 实现:
from torch.utils.checkpoint import checkpoint def forward(self, x): return checkpoint(self._forward, x) # 包装原始前向函数 -
混合精度训练(AMP)
- 工作机制:
- 权重保持 FP32 精度
- 前向 / 反向计算使用 FP16
- 梯度更新前转换回 FP32
-
1080ti 特别配置(无 Tensor Core):
scaler = torch.cuda.amp.GradScaler() # 需手动缩放损失 with torch.autocast(device_type='cuda', dtype=torch.float16): outputs = model(inputs) loss = criterion(outputs, labels) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() -
Batch Size 调优公式
max_batch = (显存总量 - 模型静态占用) / (样本显存系数 × (1 + 梯度积累步数)) - 其中样本显存系数可通过空跑单个样本测得
代码实战:BERT 微调
# 1. 环境监控工具
class GPUMonitor:
@staticmethod
def get_memory():
return torch.cuda.memory_allocated() / 1024**2 # MB
# 2. 模型初始化
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
model.gradient_checkpointing_enable() # 启用检查点
# 3. 训练循环(关键参数加粗)optimizer = AdamW(model.parameters(), lr=5e-5)
scaler = GradScaler()
for epoch in range(3):
for step, batch in enumerate(train_loader):
inputs = {k: v.to(device) for k, v in batch.items()}
with autocast(device_type='cuda', dtype=torch.float16):
outputs = model(**inputs)
loss = outputs.loss / **gradient_accumulation_steps**
scaler.scale(loss).backward()
if (step + 1) % **gradient_accumulation_steps** == 0:
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()
torch.cuda.empty_cache() # 清理碎片化显存
print(f"Step {step}: Memory used: {GPUMonitor.get_memory():.2f}MB")
性能对比测试
| 精度模式 | Batch Size | 吞吐量(samples/sec) | 显存占用(GB) |
|---|---|---|---|
| FP32 | 8 | 42.3 | 9.8 |
| FP16 | 16 | 78.6 (+85.8%) | 6.2 (-36.7%) |
测试条件:序列长度 =128, 1080ti GPU 利用率稳定在 92-98%
系统监控与排错
- 显存泄漏检测
- 监控命令组合:
watch -n 1 "nvidia-smi --query-gpu=memory.used --format=csv" -
可疑现象:每个 epoch 后显存占用持续增加 0.1-0.3GB
-
OOM 排查流程
- 立即检查项:
- 是否有未释放的 CUDA tensor(
torch.cuda.memory_summary()) - DataLoader 是否设置
pin_memory=False - 梯度积累步数是否过大
- 是否有未释放的 CUDA tensor(
- 长期优化:
- 采用
del主动释放中间变量 - 使用
with torch.no_grad()包裹验证代码
- 采用
延伸思考
- 当使用梯度检查点时,如何确定最优的检查点间隔(checkpoint segment)?
- 在混合精度训练中,如果出现梯度下溢(underflow),应如何调整 GradScaler 的参数?
- 对于超长序列输入(>512 token),有哪些显存优化策略可以组合使用?
正文完
发表至: 未分类
近一天内

