为什么PyTorch已移模型数据至CUDA但GPU无占用、运行慢于CPU
问题原因与解决方案
核心问题根因
- 任务计算量远小于数据传输开销:你的场景仅包含单神经元线性层、总共800条训练样本、batch size仅为16,GPU的并行计算能力完全没有发挥空间,反而每次CPU和GPU之间的张量拷贝、异步调度开销远大于实际计算耗时,因此出现GPU利用率极低、总耗时高于CPU的情况。
- 不必要的跨设备数据交互:代码中每次迭代都执行
loss.tolist()将GPU张量转回CPU侧的Python数值,后续还用Numpy计算损失均值,频繁打断CUDA异步执行流,额外增加了大量开销。 - 数据加载逻辑冗余:当前每次迭代都逐批次将CPU张量迁移到GPU,未利用数据集规模极小的特点提前把全量数据放到显存,进一步放大了传输开销。
可直接落地的优化方案
1. 调整数据加载逻辑,提前把全量数据放到GPU
修改create_data函数,接收device参数,创建张量时直接放到对应设备,避免每批次传输:
def create_data(device): # 直接在创建张量时指定设备,不需要后续逐批次迁移 x_train_tensor = torch.as_tensor(x_train, dtype=torch.float, device=device) y_train_tensor = torch.as_tensor(y_train, dtype=torch.float, device=device) train_data = TensorDataset(x_train_tensor,y_train_tensor) train_loader = DataLoader(dataset=train_data, batch_size=16, shuffle=True) return train_loader
对应的mini_batch函数调用时传入device即可。
2. 减少跨设备数据传输频次
修改损失统计逻辑,不要每步都把loss转回CPU,所有损失计算先在GPU侧完成,最后统一导出到CPU:
def make_train_step(model, loss_fn, optimizer): def perform_train_step(x,y): model.train() yhat = model(x) loss = loss_fn(yhat, y) loss.backward() optimizer.step() optimizer.zero_grad() # 直接返回GPU张量,不转Python数值 return loss.detach() return perform_train_step def mini_batch(step, device): mini_batch_losses=[] train_loader = create_data(device) for x_batch, y_batch in train_loader: mini_batch_loss = step(x_batch,y_batch) mini_batch_losses.append(mini_batch_loss) # 所有损失在GPU侧求平均后再转CPU数值 loss = torch.mean(torch.stack(mini_batch_losses)).item() return loss
3. 验证CUDA环境可用性
如果调整后GPU利用率仍然偏低,可以运行以下测试代码验证CUDA配置是否正常:
import torch # 执行大矩阵乘法,观察GPU利用率是否能达到70%以上 a = torch.randn(4096, 4096, device='cuda') b = torch.randn(4096, 4096, device='cuda') for _ in range(100): c = torch.matmul(a, b) torch.cuda.synchronize()
如果执行上述代码时GPU利用率显著上升,说明环境配置无问题,之前的性能问题完全是任务规模过小导致的。如果利用率仍然为0,需要确认你安装的PyTorch是CUDA版本,而非CPU版本,可以执行print(torch.version.cuda)查看PyTorch绑定的CUDA版本是否和你安装的CUDA Toolkit版本匹配。
补充说明
如果你的任务就是小样本小模型的场景,实际上不需要强制使用GPU,CPU的执行效率会更高。GPU的优势是处理大batch、大模型、大量计算的场景,任务规模足够大时才能体现出性能优势。
内容的提问来源于stack exchange,提问作者hanisalah
相关产品推荐
相关产品推荐

