ONNXRUNTIME_EXCEPTION : Non-zero status code returned while running Where node. Name:‘Where‘

本文详细介绍了在ONNX模型转换过程中遇到的错误处理,如InvalidArgument和RuntimeException,并提供了使用Netron工具检查模型网络图的方法。重点讨论了torch.where、torch.gather和torch.split等Tensor运算,解释了它们的功能和用法。对于torch.where,它是条件选择操作;torch.gather用于按索引收集数据;torch.split则用于将张量切分成多个块。理解并正确使用这些运算能有效解决ONNX转换问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

遇到此类错误,如:

onnxruntime.capi.onnxruntime_pybind11_state.InvalidArgument: [ONNXRuntimeError] : 2 : INVALID_ARGUMENT : Non-zero status code returned while running Gather node. Name:'Gather_4445' Status Message: indices element out of data bounds, idx=8 must be within the inclusive range [-3,2]

或:

RUNTIME_EXCEPTION : Non-zero status code returned while running Where node. Name:'Where' Status Message...

可以配合Netron工具(安装方法:pip install netron,使用时终端输入netron)查看导出的onnx模型网络图,可以查找相应的Node(如:Where_XXXX),再去代码中找对应代码,将其改为onnx支持的tensor运算方式即可解决相应问题。

根据在ONNX导出时遇到的问题比较麻烦的是和torch.gather、torch.where、torch.split等Tensor运算方法。

1. torch.where函数

torch.where(condition,x,y)->tensor

当满足condition,则来自于a,反之来自b

import torch
condition=torch.randn(2,2)
# tensor([[ 0.2589, -0.5600],
#        [ 0.9056, -0.3915]])
a=torch.tensor([[0,0],[0,0]])
b=torch.tensor([[1,1],[1,1]])
torch.where(cond>0.5,a,b)

得到结果

tensor([[1, 1],
        [0, 1]])

输出为0的代表来源为a,输出为1的代表来源为b

2. torch.gather(查表的过程)

torch.gather(input,dim,index,out=None)->tensor

就像是给了数据以后,查表得到对应参数,再收集回来进行输出。

gather函数即为gather(对应的参数表,dim,数据表)

import torch
prob=torch.randn(4,4)
#tensor([[-0.9845,  0.5094, -0.5014, -0.5354],
#        [-1.8514,  0.2640,  0.7895, -0.1660],
#        [ 0.3955,  0.7571,  0.1451,  0.1970],
#        [ 0.3674, -0.8006, -0.5625,  1.3455]])
idx=prob.topk(dim=1,k=2)
idx=idx[1]
#tensor([[1, 2],
#        [2, 1],
#        [1, 0],
#        [3, 0]]))
label=torch.arange(4)+100
#tensor([100, 101, 102, 103])
torch.gather(label.expand(4,4),dim=1,index=idx.long())

 输出结果:

tensor([[101, 102],
        [102, 101],
        [101, 100],
        [103, 100]])

3. torch.split

含义:将一个张量分为几个chunks

torch.split(tensor, split_size_or_sections, dim=0)

参数

  • tensor(Tensor) -张量分裂。

  • split_size_or_sections(int) 或者(list(int)) -单个块的大小或每个块的大小列表

  • dim(int) -沿其分割张量的维度。

如果split_size_or_sections 是整数类型,那么tensor将被分成大小相等的块(如果可能)。如果沿给定维度 dim 的张量大小不能被 split_size 整除,则最后一个块会更小。

如果 split_size_or_sections 是一个列表,那么 tensor 将根据 split_size_or_sections 被拆分为大小在 dim 中的 len(split_size_or_sections) 块。

示例:

>>> a = torch.arange(8).reshape(4,2)
>>> a
tensor([[0, 1],
        [2, 3],
        [4, 5],
        [6, 7]])
>>> torch.split(a, 3)
(tensor([[0, 1],
         [2, 3],
         [4, 5]]),
 tensor([[6, 7]]))
>>> torch.split(a, [1,3])
(tensor([[0, 1]]),
 tensor([[2, 3],
         [4, 5],
         [6, 7]]))

4. Tensor.scatter_函数

TORCH.TENSOR.SCATTER_

Tensor.scatter_(dimindexsrcreduce=None) → Tensor

Writes all values from the tensor src into self at the indices specified in the index tensor. For each value in src, its output index is specified by its index in src for dimension != dim and by the corresponding value in index for dimension = dim.

For a 3-D tensor, self is updated as: 

self[index[i][j][k]][j][k] = src[i][j][k]  # if dim == 0
self[i][index[i][j][k]][k] = src[i][j][k]  # if dim == 1
self[i][j][index[i][j][k]] = src[i][j][k]  # if dim == 2
This is the reverse operation of the manner described in gather().

selfindex and src (if it is a Tensor) should all have the same number of dimensions. It is also required that index.size(d) <= src.size(d) for all dimensions d, and that index.size(d) <= self.size(d) for all dimensions d != dim. Note that index and src do not broadcast.

Moreover, as for gather(), the values of index must be between 0 and self.size(dim) - 1 inclusive.

Parameters

  • dim (int) – the axis along which to index

  • index (LongTensor) – the indices of elements to scatter, can be either empty or of the same dimensionality as src. When empty, the operation returns self unchanged.

  • src (Tensor or float) – the source element(s) to scatter.

  • reduce (stroptional) – reduction operation to apply, can be either 'add' or 'multiply'.

总结:scatter函数就是把src数组中的数据重新分配到output数组当中,index数组中表示了要把src数组中的数据分配到output数组中的位置,若未指定,则填充0.

举例:

>>> src = torch.arange(1, 11).reshape((2, 5))
>>> src
tensor([[ 1,  2,  3,  4,  5],
        [ 6,  7,  8,  9, 10]])
>>> index = torch.tensor([[0, 1, 2, 0]])
>>> torch.zeros(3, 5, dtype=src.dtype).scatter_(0, index, src)
tensor([[1, 0, 0, 4, 0],
        [0, 2, 0, 0, 0],
        [0, 0, 3, 0, 0]])
>>> index = torch.tensor([[0, 1, 2], [0, 1, 4]])
>>> torch.zeros(3, 5, dtype=src.dtype).scatter_(1, index, src)
tensor([[1, 2, 3, 0, 0],
        [6, 7, 0, 0, 8],
        [0, 0, 0, 0, 0]])

>>> torch.full((2, 4), 2.).scatter_(1, torch.tensor([[2], [3]]),
...            1.23, reduce='multiply')
tensor([[2.0000, 2.0000, 2.4600, 2.0000],
        [2.0000, 2.0000, 2.0000, 2.4600]])
>>> torch.full((2, 4), 2.).scatter_(1, torch.tensor([[2], [3]]),
...            1.23, reduce='add')
tensor([[2.0000, 2.0000, 3.2300, 2.0000],
        [2.0000, 2.0000, 2.0000, 3.2300]])

<think>好的,我现在遇到了ONNX Runtime中Resize节点运行时的形状不匹配错误,错误信息是{1,256,19,40}和{1,256,20,40}不匹配。首先,我需要理解这个错误的原因。Resize节点通常用于调整输入张量的尺寸,比如上采样或下采样操作。形状不匹配意味着在运行时,某个输入的预期形状与实际提供的形状不一致。 我应该先检查模型的输入和输出形状是否正确。可能是在导出模型到ONNX格式时,输入形状没有正确指定。比如,输入张量的尺寸可能被固定为某个特定值,而实际运行时提供的输入尺寸不同。这时候需要确认模型的动态轴设置是否正确,是否允许可变尺寸。 接下来,我需要查看Resize节点的参数设置。Resize操作通常需要指定目标尺寸或缩放因子。如果使用缩放因子,那么计算出来的目标尺寸可能与实际提供的张量尺寸不匹配。例如,原尺寸是19,缩放因子可能导致计算后的尺寸不是整数,从而出现四舍五入的问题,导致尺寸不一致。这时候可能需要调整缩放模式,比如使用align_corners或者改变插值方法,或者检查缩放因子的计算是否正确。 另外,ONNX Resize节点的坐标系变换模式也可能影响尺寸计算。不同的模式(如half_pixel、align_corners等)会导致不同的计算结果。需要确认模型中Resize节点的属性设置是否与实际需求一致,是否与后端推理引擎兼容。 还有可能是在模型转换过程中,某些参数被错误地修改或丢失。比如,从PyTorch或TensorFlow转换到ONNX时,Resize层的参数可能没有被正确导出。这时候需要检查转换时的代码,确保所有参数正确传递,并且使用最新的转换工具版本。 此外,错误信息提到“re-use buffer”,这可能涉及到内存复用优化的问题。ONNX Runtime可能会尝试重用之前分配的内存缓冲区,但如果形状变化导致缓冲区尺寸不足,就会抛出错误。可以尝试禁用内存优化,通过设置SessionOptions中的enable_mem_pattern为False,看看是否解决问题。 最后,如果以上方法都无效,可能需要逐步调试。比如,将模型拆分成较小的部分,单独运行Resize节点,检查输入输出的形状是否符合预期。或者使用ONNX Runtime的日志功能,查看更详细的错误信息,定位问题发生的具体位置。 总结一下,解决步骤可能包括检查输入输出形状、调整Resize参数、确认模型转换正确性、禁用内存优化以及分步调试。需要逐一排查这些可能性,找到导致形状不匹配的具体原因。</think>### ONNX Runtime中Resize节点形状不匹配错误解决方法 当遇到ONNXRuntimeError 6的Resize节点形状不匹配问题时,可按以下步骤排查: 1. **检查输入输出形状动态性** - 确认导出ONNX模型时是否启用动态轴(如`dynamic_axes`参数) - 使用Netron可视化工具检查Resize节点的输入/输出形状是否包含`dim_param`动态标记 - 示例代码验证输入尺寸: ```python import onnxruntime as ort sess = ort.InferenceSession("model.onnx") print(sess.get_inputs()[0].shape) # 应包含动态维度如[1,256,?,?] ``` 2. **分析Resize参数配置** - 检查`scales`或`sizes`参数的计算逻辑: $$ \text{输出尺寸} = \lfloor \text{输入尺寸} \times \text{scale} \rceil $$ - 验证尺寸计算示例: ```python # 原尺寸19,scale=1.0526时 print(19 * 1.0526) # 输出≈20.0 ``` - 调整参数组合: ```python # PyTorch导出示例 torch.onnx.export(..., opset_version=13) # 确保使用opset>=11支持动态尺寸 ``` 3. **坐标系模式对齐** - 确认`coordinate_transformation_mode`参数: | 模式 | 计算方式 | |---|---| | half_pixel | $x_{dst} = (x_{src} + 0.5)/scale - 0.5$ | | align_corners | $scale = (src-1)/(dst-1)$ | - 常见错误案例:PyTorch默认使用`align_corners=False`而ONNX配置为`align_corners=True` 4. **内存优化配置** - 禁用内存复用模式: ```python sess_options = ort.SessionOptions() sess_options.enable_mem_pattern = False # 关闭内存复用 ort.InferenceSession("model.onnx", sess_options) ``` 5. **分步调试验证** - 提取子模型测试Resize节点: ```bash onnxruntime-test-tool verify --node Resize --input_data test_data.npz model.onnx ``` - 使用ONNX Runtime日志分析: ```python import logging ort.set_default_logger_severity(3) # 开启Verbose日志 ``` [^1]: ONNX Runtime官方文档建议动态尺寸模型应显式指定`dynamic_axes`参数 [^2]: ONNX opset 13改进了Resize节点的尺寸计算精度
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值