PyTorch中如何将模型移动到CPU_使用.to(‘cpu’)转换设备运行
常见错误是模型与输入张量设备不一致,需手动将输入x.to('cpu');DataParallel等封装需操作model.module;.cpu()与.to('cpu')等价但推荐后者;迁移前应no_grad且及时释放GPU引用。
模型.to('cpu') 后推理结果异常或报错
常见现象是 RuntimeError: Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same,说明模型和输入张量不在同一设备。PyTorch 不会自动把输入数据也挪到 CPU,只动模型本身。
必须手动确保输入数据也调用 .to('cpu'):
model = model.to('cpu')
x = x.to('cpu') # 这一步不能省
output = model(x)
- 如果输入来自 DataLoader(尤其是用了
pin_memory=True),默认加载到 GPU,不显式移回 CPU 就会出错 - 模型里如果有缓存的中间状态(比如某些自定义层保存了
self.register_buffer('cache', ...)),也要检查这些 buffer 是否同步移动了 - 使用
.eval()前后移动设备顺序无关,但建议先.to('cpu')再.eval(),避免某些调试模式下触发未预期的 CUDA 调用
为什么 .to('cpu') 有时没效果?
最常见原因是模型对象被重新赋值或包装过,比如用了 torch.nn.DataParallel 或 torch.compile,导致原始模型引用失效。调用 model.to('cpu') 只作用于当前变量指向的对象,不递归处理封装壳。
典型错误写法:
model = torch.nn.DataParallel(model)
model.to('cpu') # ❌ 只影响 DataParallel 包装器,内部 module 还在 GPU
- 正确做法是操作
model.module.to('cpu')(对 DataParallel)或直接对原始模型实例调用 - 如果是
torch.compile(model),需在编译前就完成设备迁移,编译后的模型不能跨设备复用 - 检查是否有多处模型赋值,比如
model = load_model(...); model = model.to('cpu'),但后续又写了model = MyWrapper(model)却忘了再.to('cpu')
to('cpu') 和 cpu() 方法有啥区别?
没区别。model.cpu() 是 model.to('cpu') 的语法糖,底层完全一致,都走 to() 实现。但推荐统一用 .to('cpu'),因为:
易企秀
易企秀,一体化创意设计营销平台。超100万模板1键套用3分钟制作,随时随地完成创意设计营销。
下载
- 语义更明确,和
.to('cuda:0')、.to(device)风格统一 - 避免混淆
.cpu()和.cuda()的返回行为(它们都返回新对象,不是 in-place 修改) - 某些旧版 PyTorch 中
.cpu()对部分自定义模块支持不稳定,.to()更健壮
模型移到 CPU 后速度反而变慢?
不是设备迁移的问题,而是触发了隐式同步或数据拷贝瓶颈。典型场景是:GPU 上训练完立刻 .to('cpu'),但此时 GPU 还在忙前向/反向计算,PyTorch 会强制同步等待所有 kernel 完成,造成卡顿。
优化建议:
- 在
torch.no_grad()下做迁移,尤其推理时,避免梯度相关开销 - 如果只是临时导出权重,用
model.state_dict()拿字典再转 CPU,比整模型迁移更快 - 注意
.to('cpu')返回的是新模型对象,原模型仍在 GPU 占着显存——记得删掉或覆盖引用,否则显存不释放
设备迁移本身不耗时,真正拖慢的是等 GPU 空闲 + 大量参数从显存拷到内存的过程,尤其是模型大、PCIe 带宽低的时候,这点容易被忽略