Unsupported: ONNX export of convolution for kernel of unknown shape

参考案例1

[onnx]Unsupported: ONNX export of convolution for kernel of unknown shape · Issue #98497 · pytorch/pytorch · GitHub

import torch

class Filter(nn.Module):
    def __init__(self):
        super().__init__()
        self.resample_filter = torch.rand(4,4)

    def forward(self, x):
        x = torch.nn.functional.pad(x, [1, 1, 1, 1])  # If this line is commented out, it works.
        weight = self.resample_filter[None, None].repeat([x.shape[1]  , 1] + [1] * self.resample_filter.ndim)
        x = torch.nn.functional.conv2d(input=x, padding=1, weight=weight, groups=x.shape[1] )
        return x


x = torch.rand((1, 3, 256, 256))
f = Filter()
y = f(x)
torch.onnx.export(f, x, "test-filter.onnx", opset_version=15)

错误信息

  File "/root/miniconda3/lib/python3.9/site-packages/torch/onnx/symbolic_opset9.py", line 2519, in _convolution
    raise errors.SymbolicValueError(
torch.onnx.errors.SymbolicValueError: Unsupported: ONNX export of convolution for kernel of unknown shape.  [Caused by the value '28 defined in (%28 : Float(*, *, *, *, strides=[199692, 66564, 258, 1], requires_grad=0, device=cpu) = onnx::Pad[mode="constant"](%0, %27, %3), scope: __main__.Filter:: # /mnt/f/codes/onnx_export/test.py:10:0
)' (type 'Tensor') in the TorchScript graph. The containing node has kind 'onnx::Pad'.]

这种问题一般出现在卷积的权重不是常规的直接的训练参数,而是从其他计算分支计算得到。

调试:

进入上面torch/onnx/symbolic_opset9.py", line 2519加入打印:

错误提示为Caused by the value '28 defined in (%28 : Float(*, *, *, *, strides=[199692, 66564, 258, 1], requires_grad=0, device=cpu)

从%28一直往上跟踪找到第一个出现*未知shape的位置:

  %28 : Float(*, *, *, *, strides=[199692, 66564, 258, 1], requires_grad=0, device=cpu) = onnx::Pad[mode="constant"](%0, %27, %3), scope: __main__.Filter:: # /mnt/f/codes/onnx_export/test.py:10:0
这里指示了是test.py第10行引起的,也就是pad那一句导致的。

这其实是底层infer shape的bug。

一种解决方案是去底层支持infer shape。

另一种是采取一些方法规避,使得进入conv前的shape是已知的,我们加入一个reshape 算子:

class Filter(nn.Module):
    def __init__(self):
        super().__init__()
        self.resample_filter = torch.rand(4, 4)

    def forward(self, x):
        x = torch.nn.functional.pad(x, [1, 1, 1, 1])  # If this line is commented out, it works.
        shape = x.shape
        shape = [int(elem) for elem in shape]
        x = x.reshape(shape)

        weight = self.resample_filter[None, None].repeat([x.shape[1], 1] + [1] * self.resample_filter.ndim)
        x = torch.nn.functional.conv2d(input=x, padding=1, weight=weight, groups=x.shape[1])
        return x

注意改动为3行:

        shape = x.shape
        shape = [int(elem) for elem in shape]
        x = x.reshape(shape)
这使得x的shape重新被完全静态确定。

改动后该代码可以进行导出。

有时候工程代码太复杂,不知道pad在哪里,那就直接去torch 的pad代码forward里面插入上面的语句。例如:

torch.onnx.errors.SymbolicValueError: Unsupported: ONNX export of convolution for kernel of unknown shape.  [Caused by the value '2004 defined in (%2004 : Float(*, *, *, *, strides=[1102464, 5742, 87, 1], requires_grad=0, device=cuda:0) = onnx::Pad[mode="constant"](%xi, %2002, %2003), # /root/miniconda3/lib/python3.9/site-packages/torch/nn/modules/padding.py:205:0

那就直接去torch/nn/modules/padding.py:205:0插入上面代码。

类似的解决方案还可以考虑替换为底层没有infer shape bug的算子。例如把上面的pad改为concat算子。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Luchang-Li

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值