Channel determination behind the Conv2D layer when export as onnx

I am trying to convert this type of code to onnx format.

     def __init__(self):
         ...
         self.conv = nn.Conv2d(c_in, c_out, 3, 1, 1)
         self.norm = nn.InstanceNorm2d(c_out)
         ...
     def forward(self, x):
         ...
         x = self. norm(self. conv(x))
         ...

Of course, I think that the result of self.conv(x) should have the form of (*, c_out, *, *).

However, this model gives the following error.
torch.onnx.errors.SymbolicValueError: Unsupported: ONNX export of instance_norm for unknown channel size.

Shouldn’t the channel be confirmed the moment self.conv is passed, no matter how other operations before it are configured? However, torch.onnx.export judges the output passed through self.conv as Float(*, *, *, *). How to solve it?

I cannot reproduce the issue and get:

class MyModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv = nn.Conv2d(1, 3, 3, 1, 1)
        self.norm = nn.InstanceNorm2d(3)
         
    def forward(self, x):
        x = self. norm(self. conv(x))
        return x
    
model = MyModel()
x = torch.randn(1, 1, 224, 224)
out = model(x)


torch.onnx.export(model, x, "test.onnx")
# ============= Diagnostic Run torch.onnx.export version 2.0.0+cu118 =============
# verbose: False, log level: Level.ERROR
# ======================= 0 NONE 0 NOTE 0 WARNING 0 ERROR ========================
# UserWarning: ONNX export mode is set to TrainingMode.EVAL, but operator 'instance_norm' is set to train=True. Exporting with train=True.

torch.onnx.export(model.eval(), x, "test.onnx")
# ============= Diagnostic Run torch.onnx.export version 2.0.0+cu118 =============
# verbose: False, log level: Level.ERROR
# ======================= 0 NONE 0 NOTE 0 WARNING 0 ERROR ========================

Of course, it worked well when I exported only those two layers. However, there was a problem when there were more layers in front. But shouldn’t the number of channels be fixed regardless of the front-end layers as soon as it passes through the Conv2D? The model I am currently trying is the OcclusionAwareSPADEGenerator from SadTalker/generator.py at main · Winfredy/SadTalker · GitHub . The error in the main text occurs when passing through the InstanceNorm2D on line 143, after going through the Conv2D on line 142.

Additionally, I am working with PyTorch 1.13.1+cu17.

That wasn’t clear from your description, so could you post a minimal and executable code snippet reproducing the issue, please?

Due to the complexity of the model, I couldn’t figure out where exactly the problem was occurring. See the picture below for the problematic part.


In the middle part of the model, there is a part that goes through Conv2D and then InstanceNorm2D. (L142-L143 written in the comments above). I couldn’t understand the error like torch.onnx.errors.SymbolicValueError: Unsupported: ONNX export of instance_norm for unknown channel size. because both layers have their channels determined. Although there is a complicated process above, isn’t the channel determined the moment it goes through Conv2D?


To be more clear, when the model is exported up to SadTalker/src/facerender/modules/generator.py at 9c36c32e64dc7beedae26790bb2795d729abbea7 · OpenTalker/SadTalker · GitHub, the size of the output is *,512,*,*. (The corresponding line is the Conv2D layer.) However, ifI execute x = self.G_middle_0.norm_0(x, seg) (InstanceNorm2D) in the next line, an error occurs.

As a result of a little more detailed analysis, it was a problem related to ONNX Opset 16 GridSample Does Not Support 5D Volumetric Input Tensor · Issue #92209 · pytorch/pytorch · GitHub. As a result of exporting with pytorch2.0, the PR was reflected and an error occurred that grid sample for 5D tensor is not supported.
However, with torch<2.0, instance_norm throws an error after passing the grid sample without problems. I think it should be a backport.

Any update on the sadtalker onnx model? I also try and got same error.