如何解决PyTorch RuntimeError: 张量分属cpu和cuda:0设备报错
报错根因
该设备不匹配报错由3处代码错误导致,和权重文件本身无关:
- 变量名混用是本次报错的核心诱因:加载模型时你新实例化的对象变量名为
model,但修改分类头、循环推理时调用的都是训练阶段遗留的model_ft变量,两个是完全独立的对象。你检查到在GPU上的是新加载的model,实际跑前向传播的model_ft设备状态、结构、权重都和你预期的不一致。 - 张量设备未对齐:推理循环中你仅将输入
inputs移到了GPU,labels默认加载在CPU;同时模型输出的预测索引indices属于GPU张量,你直接将其赋值给CPU内存初始化的y_pred张量,触发跨设备操作报错。 - 冗余设置:
model.eval()被放在循环内部,每次迭代都会重复调用,虽然不会直接触发报错,但属于无意义的冗余操作。
修正后可运行代码
模型加载段
import torch import torch.nn as nn from torchvision import models # 统一使用model_ft作为模型实例变量名,避免和旧变量混淆 model_ft = models.densenet161(pretrained=False, num_classes=11) # 显式指定分类头结构,和训练时保持一致 model_ft.classifier = nn.Linear(2208, 11) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # 加载权重时直接映射到目标设备,避免额外的设备转换开销 model_ft.load_state_dict(torch.load('/content/drive/My Drive/Stanford40/densenet161.pth', map_location=device)) model_ft = model_ft.to(device) # 评估模式仅需设置一次,移到循环外部 model_ft.eval()
评估推理段
from torchvision import datasets test_dataset = datasets.ImageFolder('/content/drive/My Drive/Stanford40/body/valid', transform=data_transforms['valid']) test_dataloader = torch.utils.data.DataLoader(test_dataset, batch_size=1, shuffle=True) class_names = test_dataset.classes sample_count = len(test_dataset) # 初始化结果存储张量时直接分配到对应设备,避免跨设备赋值报错 y_true = torch.zeros((sample_count, 1), device=device) y_pred = torch.zeros((sample_count, 1), device=device) # 关闭梯度计算,降低显存占用、提升推理速度 with torch.no_grad(): for idx, (inputs, labels) in enumerate(test_dataloader): # 输入、标签均迁移到目标设备 inputs = inputs.to(device) labels = labels.to(device) outputs = model_ft(inputs) y_true[idx][0] = labels _, pred_indices = torch.max(outputs, dim=1) y_pred[idx][0] = pred_indices # 后续如果需要用CPU端的库(如sklearn)计算指标,再将结果迁回CPU即可 # y_true = y_true.cpu().numpy() # y_pred = y_pred.cpu().numpy()
关键修改说明
- 全程统一模型变量名为
model_ft,彻底解决新旧变量混用导致的模型对象不匹配问题,从根源上避免“模型在GPU但实际推理用的是CPU上另一个模型”的问题 - 加载权重时增加
map_location=device参数,确保权重直接加载到目标设备,不会出现权重先加载到CPU再迁移的中间状态问题 - 所有参与运算的张量(输入、标签、结果存储张量)均分配到和模型一致的设备上,完全消除跨设备操作的可能
- 增加
torch.no_grad()上下文管理器,推理阶段不保存梯度,可大幅降低显存占用 - 直接通过数据集对象的内置方法获取样本总数,不依赖外部可能未定义的
dataset_sizes变量,减少额外报错可能
内容的提问来源于stack exchange,提问作者Ace198
相关产品推荐
相关产品推荐

