原帖在 np.flip 或 np.rot90 结果上调用 torch.from_numpy 失败:
RuntimeError: some of the strides of a given numpy array are negative. This is currently not supported, but will be added in future releases.
负步长是内存访问方向,不是数值符号
np.flip 可能只是沿反向读取同一块存储,array.strides 因而含负数。把图像像素转正或改 dtype 不会改变这种布局。应在从 NumPy 进入 Tensor 的边界处理视图,保留原来翻转的增强含义。
NumPy 的翻转可以生成负步长视图,数据未必复制。这里要检查的是数组的 strides,不是像素中有负值。
下面是独立的最小示例:
import numpy as np
import torch
x = np.arange(24, dtype=np.float32).reshape(3, 4, 2)
flipped = np.flip(x, axis=0)
print("josh050608")
print("shape/strides:", flipped.shape, flipped.strides)
print("contiguous:", flipped.flags.c_contiguous)
array = flipped.copy()
tensor = torch.from_numpy(array)
assert np.array_equal(tensor.numpy(), flipped)
对原题可直接改成 torch.from_numpy(np.flip(x, axis=0).copy())。也可在通用数据入口对需要转换的视图调用 np.ascontiguousarray,并检查转换后的步长为受支持布局;明确的 .copy() 更直接表达这里要复制翻转结果。
另一条路径是先从正常数组建立 Tensor,再使用 torch.flip(tensor, dims=(0,)),把翻转留在 PyTorch 中。它与 NumPy 负步长视图在存储行为上并不相同,不能依赖两者一定共享同一份内存。
如果负步长出现在 Dataset 的图像增强中,把复制放在 from_numpy 前,而不是等默认 collate 报错后再修。验证形状与翻转顺序正确、首尾样本确实交换;不要通过去掉翻转来悄悄改变训练增强。原错误里的“未来会支持”是历史措辞,不能作为当前版本已支持的保证。
同时验证布局和翻转后的顺序
下面扩展到两种翻转方向,复制后比较值与首尾位置。CPU 即可运行:
import numpy as np
import torch
source = np.arange(12, dtype=np.float32).reshape(3, 4)
for axis in (0, 1):
view = np.flip(source, axis=axis)
assert any(stride < 0 for stride in view.strides)
contiguous = view.copy()
assert all(stride >= 0 for stride in contiguous.strides)
tensor = torch.from_numpy(contiguous)
assert np.array_equal(tensor.numpy(), view)
reference = torch.flip(torch.from_numpy(source), dims=(axis,))
assert torch.equal(tensor, reference)
print("axis/strides:", axis, view.strides, contiguous.strides)
真实图像若是 HWC,左右翻转应按 W 对应的轴;若是 CHW,轴号不同。复制解决布局支持,不能替你判断翻转方向是否正确。分割或检测增强还要同步变换掩码、框或关键点。
在 Dataset.getitem 的 from_numpy 前统一做这次布局处理,可避免错误在 DataLoader 默认组批中才暴露。若后续还会对数组原地修改,要同时考虑 from_numpy 与数组共享存储的行为,必要时明确保留独立副本。
最终检查 shape、dtype、像素顺序以及标注同步,而不是仅确认 strides 不再为负。原错误的“未来将支持”是当时文字,应通过实际版本验证,不能视为当前安装的承诺。
参考:原始求助帖;技术依据:torch.from_numpy(2.5)、NumPy 连续数组。