grad can be implicitly created only for scalar outputs:修复 stack 后还要选择求导目标

简介: 本文解析PyTorch中`backward()`报错“grad can be implicitly created only for scalar outputs”的根本原因:一是用`FloatTensor`重建中断计算图,二是`stack`后输出向量需显式指定标量目标(如`sum()`、`mean()`或权重)。强调应先明确数学目标(如求导对象),再选择合理reduction,而非盲目绕过错误。

原帖先把逐元素平方结果重新包装成 FloatTensor,丢失计算图;改成 stack 后,又在向量上直接 backward:

RuntimeError: grad can be implicitly created only for scalar outputs

图连接修复之后,还要指定反向含义

原题先重新构造 FloatTensor 断图,换成 stack 后则得到向量输出。向量本身没有唯一的“梯度”,backward 需要一个标量目标或显式上游权重。选择 sum、mean 或加权和会得到不同结果,应按数学目标决定。

这是一前一后两个问题。索引和 clone 本身可以保留梯度;重新从结果列表构造普通 Tensor 会切断连接,而修好连接后,向量输出仍需明确反向的权重。

下面用原题的一维平方构造可运行示例:

import torch
x = torch.tensor([1., 2., 3., 4., 5.], requires_grad=True)
x_cloned = x.clone()
A = torch.stack([value.square() for value in x_cloned])
print("josh050608")
print("A:", A.shape, A.requires_grad, A.grad_fn)
print("x/clone leaf:", x.is_leaf, x_cloned.is_leaf)
A.sum().backward()
assert torch.allclose(x.grad, 2 * x.detach())
print("x gradient:", x.grad)

这里求的是各项平方和对 x 的导数,理论上为 2x。A.backward(torch.ones_like(A)) 表达同样的向量加权和,但不要在已经释放的同一张图上再调用第二次 backward;需要新的前向或有意保图。

如果实际目标是每个输出对每个输入的完整 Jacobian,求和并不会直接返回这张矩阵,应使用相应 Jacobian 接口或逐项求导。先明确数学目标,再选 reduction。

x_cloned 通常是非叶子,它的 .grad 默认不保留;应查看原叶子 x.grad。只有确实需要检查中间梯度时,才在反向前对中间张量调用 retain_grad。

原题不需要 Variable。最终验证既要看 A 有 grad_fn,也要用简单可解析函数核对梯度,避免只把两个报错先后绕过去。

sum、mean、显式权重的解析对照

下面每次重新建立前向图,验证平方函数的三种导数,不对已经释放的同一图反向两次:

import torch
values = torch.tensor([1., 2., 3.])
for mode in ("sum", "mean", "weighted"):
    x = values.clone().requires_grad_()
    output = x.square()
    if mode == "sum":
        output.sum().backward()
        expected = 2 * values
    elif mode == "mean":
        output.mean().backward()
        expected = 2 * values / values.numel()
    else:
        weights = torch.tensor([1., 0., 2.])
        output.backward(weights)
        expected = 2 * values * weights
    assert torch.allclose(x.grad, expected)
    print(mode, x.grad.tolist())

显式权重对应向量与权重内积的导数,不是完整 Jacobian。若要逐输出、逐输入的矩阵,应按所用版本选 Jacobian 接口或有意逐项求导,不能用 ones_like 代替全部数学含义。

将已有可求导 Tensor 列表重新交给 torch.tensor 或旧 FloatTensor 构造,会把数值拿出来重建新对象;组合计算结果应使用 stack、cat 或直接向量化运算。索引与 clone 本身不必切断梯度,检查 grad_fn 可以把这两类操作区分开。

验收用解析函数核对梯度值,再迁回真实函数;若中间 clone 的 grad 为 None,先看它是否非叶子,所需最终梯度通常保存在原叶子 x。不要仅为消除报错随意加 sum 而不解释求导目标。

参考:原始求助帖;技术依据:Tensor.backward(2.5)、PyTorch 自动求导(2.5)、torch.stack(2.5)、Tensor.is_leaf(2.5)。

相关文章
|
2天前
|
PyTorch API 算法框架/工具
Expected 4-dimensional input, got [3,224,224]:单张图片也要保留 batch 维
Inception等PyTorch模型要求输入为`[N,C,H,W]`格式,单张CHW图像(如`[3,224,224]`)需用`unsqueeze(0)`添加batch维,变为`[1,3,224,224]`,不可误拆通道或滥用`view`。注意预处理、设备/类型对齐及输出结构解析。(239字)
|
2天前
|
缓存 Unix PyTorch
OSError: [Errno 24] Too many open files:两个 DataLoader 可以 zip,先查文件描述符
原帖双Loader并发读取ZIP导致“Too many open files”(Errno 24),实为文件描述符泄漏或生命周期管理不当,非ZIP不支持DataLoader。需排查Dataset中图像/HDF5/ZIP句柄是否及时释放,并优先采用单Loader配对Dataset保障数据一致性与资源可控性。(239字)
|
2天前
|
并行计算 PyTorch 算法框架/工具
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的设备。
|
2天前
|
并行计算 PyTorch Linux
libtorch_python.so: cannot open shared object file:文件缺失时先修复 torch 安装
该问题核心是 PyTorch 1.0.1.post2 安装不完整,`torch/lib/` 下缺失关键文件 `libtorch_python.so`,非环境变量(LD_LIBRARY_PATH)可解决。需先用 `importlib.util.find_spec` 定位真实安装路径,核对文件存在性;再通过 `pip show -f torch` 验证分发完整性。切勿混用版本或复制库文件。
|
2天前
|
并行计算 PyTorch Linux
RuntimeError: CUDA error: device-side assert triggered:Colab 先重启,再找首次断言
该文详解CUDA断言错误调试策略:强调先重启运行时、启用`CUDA_LAUNCH_BLOCKING=1`,用最小张量验证环境;区分“会话已坏”与新操作触发,主张逐段定位而非臆测标签越界,提供实用边界检查函数与验证流程。(239字)
|
2天前
|
并行计算 PyTorch 异构计算
can’t convert CUDA tensor to numpy:只取分类索引时直接用 torch.argmax
原帖因直接对CUDA张量调用`.data.numpy().argmax()`报错:“无法将CUDA张量转为NumPy”。正确做法是:在GPU上用`output.argmax(dim=1).item()`获取单图预测索引,避免全量拷贝,仅传回标量,高效且安全。(239字)
|
2天前
|
PyTorch 算法框架/工具 索引
ValueError: only one element tensors can be converted to Python scalars:张量列表先检查形状,再 stack
该文解析PyTorch中`list(tensor)`引发的`ValueError`根源:列表含多元素张量时,不可直接转Python标量。强调应通过`tensor.shape`或遍历打印各张量尺寸来查形状;同形张量用`torch.stack`(增维)而非`cat`或`item`;异形则保留原结构,避免强行转换。
|
2天前
|
数据可视化 PyTorch 算法框架/工具
only batches of spatial targets supported:三通道分割 one-hot 转为每像素类别编号
该报错源于PyTorch交叉熵要求标签为`[N, H, W]`(3D),但输入了`[N, 3, H, W]`(4D)掩码。需先验证三通道是否为互斥one-hot,再用`argmax(dim=1)`转为整型标签,并妥善处理全零未标注像素(设`ignore_index`),避免误判为背景类。(239字)
|
2天前
|
PyTorch 算法框架/工具 异构计算
Expected object of scalar type Float but got scalar type Double for argument #4 'mat1':NumPy 输入与 Linear 权重怎样统一类型
PyTorch中`RuntimeError: Expected Float but got Double`常因输入Tensor(float64)与模型权重(float32)类型不一致导致。关键在第一层Linear的输入与权重dtype需统一:可将数据转为float32(推荐),或模型整体升为float64。务必检查`tensor.dtype`而非数值显示,并确保`loss.backward()`前类型已对齐。(239字)
|
2天前
|
机器学习/深度学习 索引
The size of tensor a (133) must match tensor b (10):分类任务换 MSELoss 后先查标签含义
原帖网络输出133类logits,CrossEntropyLoss支持类别索引输入(如`[10]`),而MSELoss要求`outputs`与`target`形状严格匹配(如`[10,133]`)。报错因`target`为`[10]`,无法广播匹配`[10,133]`输出,本质是两类损失对标签格式约定不同。

热门文章

最新文章