通过结合16位(FP16)和32位(FP32)浮点格式,在保持模型精度的同时减少内存占用。PyTorch的torch.cuda.amp模块提供原生支持,核心是autocast()(自动选择精度)和GradScaler(梯度缩放,避免FP16下溢)。
实现示例:
from torch.cuda.amp import autocast, GradScaler
model = MyModel().cuda()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
scaler = GradScaler()
for data, target in data_loader:
optimizer.zero_grad()
with autocast(): # 自动选择FP16/FP32
output = model(data)
loss = loss_fn(output, target)
scaler.scale(loss).backward() # 缩放梯度防止下溢
scaler.step(optimizer) # 更新参数
scaler.update() # 调整缩放因子
优势:内存占用减少约50%,训练速度提升明显,尤其适合Transformer、CNN等模型。
通过在前向传播中仅存储部分中间激活值,反向传播时重新计算缺失的激活值,以时间换空间。适用于超大规模模型(如BERT、GPT)。
实现示例:
from torch.utils.checkpoint import checkpoint
def checkpointed_segment(input_tensor):
# 需要重计算的模型段
return model_segment(input_tensor)
output = checkpoint(checkpointed_segment, input_tensor) # 仅存储输入和输出
注意事项:会增加约20%-30%的计算时间,但能显著减少内存占用(通常减少30%-50%)。
通过多次迭代累积小批量的梯度,再更新模型参数,模拟大批次训练效果。适用于显存不足但无法增大实际批次大小的场景。
实现示例:
accumulation_steps = 4 # 累积4个小批量
for i, (data, target) in enumerate(data_loader):
output = model(data)
loss = loss_fn(output, target)
loss = loss / accumulation_steps # 归一化损失
loss.backward() # 累积梯度
if (i + 1) % accumulation_steps == 0:
optimizer.step() # 更新参数
optimizer.zero_grad() # 清零梯度
优势:无需修改模型结构,仅需调整训练循环,能有效提升“虚拟”批次大小。
del删除不再需要的张量,减少引用计数;torch.cuda.empty_cache()释放PyTorch缓存的内存(未归还系统,但可供后续分配);gc.collect()强制Python回收无用对象。del x, y # 删除无用张量
gc.collect() # 触发垃圾回收
torch.cuda.empty_cache() # 清空CUDA缓存
注意:empty_cache()会触发同步,影响性能,建议在调试或空闲时使用。
yield逐批加载数据,避免一次性加载全部数据到内存;torch.utils.data.DataLoader的pin_memory=True参数,将数据预加载到固定内存(Pinned Memory),加速GPU传输;x.add_(1))替代创建新张量(如x + 1)。# 数据加载器使用pin_memory
data_loader = DataLoader(dataset, batch_size=32, pin_memory=True)
# 生成器逐批读取数据
def data_generator(file_path):
with open(file_path, 'rb') as f:
while True:
data = f.read(64 * 1024)
if not data:
break
yield torch.from_numpy(np.frombuffer(data, dtype=np.float32))
优势:减少数据加载时的内存峰值,提升I/O效率。
torch.nn.parallel.DistributedDataParallel(DDP)替代DataParallel(DP),DDP通过多进程通信,避免DP的全局锁瓶颈,且内存利用率更高;import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
dist.init_process_group(backend='nccl')
model = DDP(model.cuda()) # 包装模型
优势:支持多GPU/多节点训练,线性扩展内存容量,适合超大规模模型。
nvidia-smi查看GPU显存占用,或torch.cuda.memory_summary()打印PyTorch内存详情;torch.profiler开启内存分析模式,定位内存泄漏点;valgrind检测内存泄漏。# 打印内存摘要
print(torch.cuda.memory_summary(device=None, abbreviated=False))
# 使用Profiler记录内存
with torch.profiler.profile(
activities=[torch.profiler.ProfilerActivity.CUDA],
profile_memory=True
) as prof:
# 训练代码
pass
print(prof.key_averages().table(sort_by="cuda_memory_usage", row_limit=10))
优势:快速定位内存泄漏(如未释放的计算图、循环引用的张量),优化内存使用效率。
with torch.no_grad(),避免生成不必要的计算图;# 推理时禁用计算图
with torch.no_grad():
output = model(input_data)
注意:全局变量会导致中间结果无法被垃圾回收,是内存泄漏的常见原因之一。