错误根源是模型、输入数据或手动创建张量未统一设备;须在入口处定义全局device,模型、输入及所有显式张量(如torch.tensor(..., device=device))同步迁移,避免硬编码设备名,多卡需配合dataparallel或ddp。

PyTorch报错“Expected all tensors to be on the same device”怎么快速定位
这个错误不是模型没放GPU,而是模型内部某些张量(比如self.register_buffer、nn.Parameter初始化时用torch.zeros没指定device)、或输入数据、损失函数里的常量(如torch.tensor(1.0))混在了CPU和GPU之间。最典型场景是:模型.to(device)了,但input还在CPU,或者criterion里写了torch.tensor([0.1, 0.9]).to('cuda')却忘了随device变量动态切换。
统一转移的正确姿势:别只调model.to(device)
单靠model.to(device)不够——它只处理nn.Module子模块和参数,不自动递归处理你手动创建的torch.Tensor对象,也不影响输入数据流。必须同步处理三类东西:
- 模型本身:
model.to(device) - 输入数据(
data、target等):data = data.to(device),别漏掉non_blocking=True(尤其配合DataLoader(pin_memory=True)时能提速) - 所有显式构造的张量:比如损失权重、掩码、学习率调度中的临时tensor,全部用
.to(device)或直接在创建时指定device=device
示例错误写法:weight = torch.tensor([0.5, 0.5]) → 正确应为:weight = torch.tensor([0.5, 0.5], device=device)。
device变量必须全局一致且早于所有张量创建
常见坑是把device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')写在模型定义之后,甚至写在DataLoader循环里。结果就是:模型创建时默认在CPU,to(device)后部分buffer没被覆盖;或不同epoch用了不同device值(比如GPU显存不足时自动fallback到CPU,但之前张量还在GPU上)。
实操建议:
- 入口处第一行就定义
device,并打印确认:print(f"Using {device}") - 所有
torch.*构造函数(zeros、ones、tensor、arange等)都显式传device=device参数 - 避免硬编码
'cuda:0'或'cpu',全走变量
多GPU训练时model.to(device)不能替代nn.DataParallel或DistributedDataParallel
如果你用torch.cuda.device_count() > 1但只写model.to('cuda'),PyTorch默认只用cuda:0——其余GPU上的张量根本不会被创建,后续loss.backward()时反而因梯度计算跨设备报错。这时必须选一种并坚持到底:
- 单机多卡简单场景:用
model = nn.DataParallel(model).to(device)(注意device仍要是'cuda',不是'cuda:0') - 生产级/多机训练:改用
DistributedDataParallel,且每个进程绑定唯一cuda:N,model.to(device)中的device必须是该进程专属GPU - 千万别混用:
DataParallel+ 手动.to('cuda:1')会直接崩溃
检查是否真在多卡生效:运行中打印next(model.parameters()).device,它应该显示cuda:0(DataParallel下)或cuda:N(DDP下),而不是cuda这种模糊值。
最容易被忽略的是自定义nn.Module里__init__中创建的torch.Tensor——它们一旦创建就固定在初始设备上,to(device)不会自动更新。要么改用register_buffer(它会被to()同步),要么在forward里每次按需创建并指定device。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











