Expected all tensors to be on the same device, cuda:0 and cpu:恢复训练时检查 SGD 动量

简介: 该问题源于断点续训时优化器状态(如SGD动量缓冲区)未与模型参数同设备,导致`optimizer.step()`中跨设备张量运算失败。前向/反向可正常执行,但动量更新报错“cuda:0 and cpu”。需检查并统一`param`、`grad`及`optimizer.state`中所有Tensor的设备。

这道题在恢复 checkpoint 后的 optimizer.step() 失败,堆栈落在 SGD 动量更新,而不是模型前向:

RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!

为什么前向通过,step 还会失败

原帖把模型、输入与损失函数移到 GPU 后,已经走过了前向和反向;异常出现在 buf.mul_(momentum).add_(d_p, ...)。这里参与运算的是动量缓冲区和当前梯度,不只是图片与权重。检查输入设备固然有用,却覆盖不到恢复后的优化器状态。

原帖没有贴出完整加载顺序,所以“状态留在 CPU”是要用下面打印结果确认的分支。

因此即使输入、标签、模型都已上 GPU,优化器保存的动量仍值得单独检查。将下列代码放在第一次 optimizer.step() 前;optimizer 就是恢复状态后的优化器。

import torch
print("josh050608")
for group in optimizer.param_groups:
    for p in group["params"]:
        print("param/grad:", p.device, None if p.grad is None else p.grad.device)
        for key, value in optimizer.state.get(p, {
   }).items():
            if isinstance(value, torch.Tensor):
                print("state:", key, value.device, value.dtype)

若某参数在 CUDA、其 momentum_buffer 却在 CPU,就定位到了这次加法的设备冲突。优先调整恢复顺序:把模型放到目标设备,再以该模型参数创建优化器,最后加载优化器状态。checkpoint_path 是自己的可信 checkpoint 路径,Model 和优化器超参数需保持原训练定义。

device = torch.device("cuda:0")
checkpoint = torch.load(checkpoint_path, map_location="cpu", weights_only=True)
model = Model().to(device)
model.load_state_dict(checkpoint["model_state_dict"])
optimizer = torch.optim.SGD(model.parameters(), lr=lr, momentum=momentum)
optimizer.load_state_dict(checkpoint["optimizer_state_dict"])

旧版 PyTorch 没有 weights_only 参数;按该版本签名调用。原帖 checkpoint 还保存了 args 等对象,若受限加载不接受它们,应在可信来源前提下按对应版本处理,而不是对未知文件关闭检查。

对 SGD,必要时仅把确认错放的 momentum_buffer 迁到对应 p.device。不要把所有优化器的状态一律搬动,一些优化器允许 CPU 上的标量计数。再做一次前向、反向和 step,重复打印确认动量与参数一致,并确认参数确实发生更新。

只修已经确认错放的 SGD 动量

若检查证实只有 SGD 的动量设备不对,在 load_state_dict 后、下一次 step 前可以显式修正:

# optimizer 是前文恢复好的 SGD;不适用于任意优化器的所有状态。
for group in optimizer.param_groups:
    for p in group["params"]:
        state = optimizer.state.get(p, {
   })
        buf = state.get("momentum_buffer")
        if buf is not None and buf.device != p.device:
            state["momentum_buffer"] = buf.to(device=p.device)

同时确认优化器实际持有的就是当前模型参数。若先建优化器,随后又把 model 重新赋值为另一个实例,优化器可能仍在更新旧对象;单纯迁移动量不能修复这种引用错误:

model_ids = {
   id(p) for p in model.parameters()}
optimizer_ids = {
   id(p) for g in optimizer.param_groups for p in g["params"]}
print("optimizer belongs to model:", optimizer_ids <= model_ids)

下面的小例子完整演示保存、重建、恢复与一次更新。使用内存文件和 CPU,不读写真实 checkpoint;它验证恢复流程,不复现 GPU 设备冲突:

import io
import torch
from torch import nn
torch.manual_seed(3)
model = nn.Linear(3, 1)
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
x, y = torch.randn(4, 3), torch.randn(4, 1)
optimizer.zero_grad()
nn.functional.mse_loss(model(x), y).backward()
optimizer.step()
buffer = io.BytesIO()
torch.save({
   "model": model.state_dict(), "optim": optimizer.state_dict()}, buffer)
buffer.seek(0)
checkpoint = torch.load(buffer, map_location="cpu", weights_only=True)
restored = nn.Linear(3, 1).to("cpu")
restored.load_state_dict(checkpoint["model"])
opt = torch.optim.SGD(restored.parameters(), lr=0.1, momentum=0.9)
opt.load_state_dict(checkpoint["optim"])
before = restored.weight.detach().clone()
opt.zero_grad()
loss = nn.functional.mse_loss(restored(x), y)
loss.backward()
opt.step()
assert not torch.equal(before, restored.weight)
for p, state in opt.state.items():
    assert state["momentum_buffer"].device == p.device
print("restored step:", float(loss.detach()))

回到 GPU 环境后,用同一小批真实数据检查梯度、动量、参数三者的设备,再确认权重变化。不要用“删除优化器状态就能跑”作为等价的断点续训验证,那会丢掉原来的动量历史。

参考:原始求助帖;技术依据:PyTorch 优化器(2.5)、PyTorch 保存与加载教程、torch.load(2.5)。

相关文章
|
11天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
4153 22
|
11天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
4210 49
|
6天前
|
存储 弹性计算 人工智能
2026 年阿里云双十一活动入口攻略,新客服务器优惠通道、三大会场入口梳理
综合来看,2026年阿里云双十一活动入口清晰: 阿里云轻量应用服务器、阿里云ECS云服务器、阿里云GPU云服务器、阿里云百炼大模型服务平台 活动会场、综合权益中心、99计划专场三大入口覆盖服务器、AI权益与续费特价;新用户通过控制台首页banner、权益中心、产品页三处路径进入专属专场,老用户通过控制台弹窗和费用中心权益中心进入老客专区,企业用户做企业实名后解锁专属满减与阶梯折扣。
821 0
|
12天前
|
iOS开发 Docker MacOS
【2026实测】Docker Desktop下载、安装、汉化、配置教程(附官网安装包)
Docker Desktop 是 Docker 官方推出的桌面容器管理工具,集成引擎、CLI、图形界面与 Kubernetes,支持 Win/macOS/Linux。2026 最新版 4.88.1 强化 ARM 原生运行、镜像加速及资源可视化,附中文汉化与国内镜像配置指南。
2024 7
|
6天前
|
云安全 人工智能 安全
|
5天前
|
Linux 开发工具 iOS开发
2026最新codex下载安装保姆级使用教程(下载+安装+登录+使用,含所有历史版本)
本文详解OpenAI Codex国内快速上手指南:提供Win/macOS/Linux全平台免安装包、npm/Homebrew等多方式安装、账号/API Key双登录、简体中文切换,覆盖下载、安装、汉化、使用及高频避坑(如微软商店失败、npm超时等),10分钟即可跑通。
1162 3
|
12天前
|
安全 算法 定位技术
《高性价比人生指南》完整原版:普通人用最少的资源,过好这一生的底层逻辑~How To Live Better
📖《高性价比人生指南》是一份基于实证、拒绝焦虑的生存手册,倡导以“人生时薪”为视角,重新计算时间、金钱与精力的成本与收益。它不承诺逆袭,只教人算清账:省下的钱若耗掉时间便亏;买体验比买物品更值;睡眠是最高杠杆的健康投资;关系贵在情绪价值而非表面热络;学习重在改变行为而非自我安慰。核心理念:用低成本、高回报的微小行动,换取长期的选择权——不是成为谁,而是掌控自己人生的主动权。
2149 6
|
云安全 安全 网络安全
|
3天前
|
人工智能 安全 API
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(dsh)是DeepSeek AI于2026年开源的轻量级Agent运行框架,基于Cordis内核,践行“一切皆插件”理念。支持Web/桌面双端,开箱即用;内置多模型接入、丰富插件生态(超3.5万),适配编程、办公、创作等场景。(239字)
765 0

热门文章

最新文章