RuntimeError: The size of tensor a (80) must match the size of tensor b (95) at non-singleton dimension 2

Thierry_Roger_Bayala: <p>Hello, I would like to understand this issue and looking for a solution to fix it. I am trying to use U-Net architecture for my project and I am getting this RuntimeError error when estimating MSE between the target and the prediction.</p>
<p>My input tensor have a shape of [1, 3, 95, 64] but when it pass through the Network, I obtained a tensor of [1, 3, 80, 64]. What can be reason of this issue.</p>
<p>Here is my Network:</p>
<p>Sequential(<br>
(0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(2): ReLU(inplace=True)<br>
(3): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(5): ReLU(inplace=True)<br>
(6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)<br>
(7): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(8): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(9): ReLU(inplace=True)<br>
(10): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(11): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(12): ReLU(inplace=True)<br>
(13): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)<br>
(14): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(15): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(16): ReLU(inplace=True)<br>
(17): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(18): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(19): ReLU(inplace=True)<br>
(20): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)<br>
(21): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(22): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(23): ReLU(inplace=True)<br>
(24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(25): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(26): ReLU(inplace=True)<br>
(27): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)<br>
(28): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(29): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(30): ReLU(inplace=True)<br>
(31): Conv2d(1024, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(32): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(33): ReLU(inplace=True)<br>
(34): ConvTranspose2d(1024, 1024, kernel_size=(2, 2), stride=(2, 2))<br>
(35): Conv2d(1024, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(36): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(37): ReLU(inplace=True)<br>
(38): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(39): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(40): ReLU(inplace=True)<br>
(41): ConvTranspose2d(512, 512, kernel_size=(2, 2), stride=(2, 2))<br>
(42): Conv2d(512, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(43): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(44): ReLU(inplace=True)<br>
(45): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(46): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(47): ReLU(inplace=True)<br>
(48): ConvTranspose2d(256, 256, kernel_size=(2, 2), stride=(2, 2))<br>
(49): Conv2d(256, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(50): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(51): ReLU(inplace=True)<br>
(52): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(53): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(54): ReLU(inplace=True)<br>
(55): ConvTranspose2d(128, 128, kernel_size=(2, 2), stride=(2, 2))<br>
(56): Conv2d(128, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(57): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(58): ReLU(inplace=True)<br>
(59): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)<br>
(60): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)<br>
(61): ReLU(inplace=True)<br>
(62): Conv2d(64, 3, kernel_size=(1, 1), stride=(1, 1))<br>
)</p>

QLYYLQ: <p>sorry, i misread the question. Just padding your input to 96,64 that may work</p>

Thierry_Roger_Bayala: <p>I added a padding as it is shown in architecture. Or it is not the correct way to do it ? I will appreciate if you can help me to add the pad correctly</p>

QLYYLQ: <p>Actually, I feel confused about that you used an input with the shape [95,64]  and successfully got the output. There should be a RuntimeError in forward function. You can see and use my example code.</p>
<pre data-code-wrap="python"><code class="lang-python">import torch
import torch.nn as nn

class DoubleConv(nn.Module):
    def __init__(self, in_channels, out_channels):
        super().__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True)
        )

    def forward(self, x):
        return self.conv(x)

class UNet(nn.Module):
    def __init__(self, in_channels=3, out_channels=1):
        super().__init__()
        
        # encoder part
        self.enc1 = DoubleConv(in_channels, 64)
        self.enc2 = DoubleConv(64, 128)
        self.enc3 = DoubleConv(128, 256)
        self.enc4 = DoubleConv(256, 512)
        
        # polling layer
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        
        # bottle neck
        self.bottleneck = DoubleConv(512, 1024)
        
        # up sampling part
        self.up1 = nn.ConvTranspose2d(1024, 512, kernel_size=2, stride=2)
        self.up2 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2)
        self.up3 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2)
        self.up4 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2)
        
        # decoder part
        self.dec1 = DoubleConv(1024, 512)
        self.dec2 = DoubleConv(512, 256)
        self.dec3 = DoubleConv(256, 128)
        self.dec4 = DoubleConv(128, 64)
        
        # output layer
        self.out = nn.Conv2d(64, out_channels, kernel_size=1)

    def forward(self, x):
        # encoder
        enc1 = self.enc1(x)
        enc2 = self.enc2(self.pool(enc1))
        enc3 = self.enc3(self.pool(enc2))
        enc4 = self.enc4(self.pool(enc3))
        
        # bottleneck
        bottleneck = self.bottleneck(self.pool(enc4))
        
        # decoder
        dec1 = self.dec1(torch.cat([self.up1(bottleneck), enc4], dim=1))
        dec2 = self.dec2(torch.cat([self.up2(dec1), enc3], dim=1))
        dec3 = self.dec3(torch.cat([self.up3(dec2), enc2], dim=1))
        dec4 = self.dec4(torch.cat([self.up4(dec3), enc1], dim=1))
        
        return self.out(dec4)


if __name__ == "__main__":
    # create a model
    model = UNet(in_channels=3, out_channels=1)
    print("Encoding path:")
    print("1. enc1:\n", model.enc1)
    print("2. pool + enc2:\n", model.pool,model.enc2)
    print("3. pool + enc3:\n", model.pool,model.enc3) 
    print("4. pool + enc4:\n", model.pool,model.enc4)

    print("\nBottleneck:\n")
    print("5. pool + bottleneck:\n", model.bottleneck)

    print("\nDecoding path:\n") 
    print("6. up1 + concat + dec1\n", model.up1, model.dec1)
    print("7. up2 + concat + dec2\n", model.up2, model.dec2)
    print("8. up3 + concat + dec3\n", model.up3, model.dec3)
    print("9. up4 + concat + dec4\n", model.up4, model.dec4)

    print("\nOutput:")
    print("10. out:", model.out)
    # random input
    x = torch.randn(1, 3, 96, 64)
    
    # forward pass
    output = model(x)
    
    print(f"Input shape: {x.shape}")
    print(f"Output shape: {output.shape}")
</code></pre>
<p>In this code, i build a same u-net with [96,64] input, i get the correct answer.</p>

QLYYLQ: <p>Also a strange thing in your code is: <code>ConvTranspose2d(128, 128, kernel_size=(2, 2), stride=(2, 2))</code>.</p>
<p>In U-Net, every upsample should half the channel number, because the upsample tensor should concatenate the same encoder tensor which is shown in U-Net architecture<br>
<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/0/4/041208fbc335dc0a3bab382328c1d66eb7723aed.png" data-download-href="https://discuss.pytorch.org/uploads/default/041208fbc335dc0a3bab382328c1d66eb7723aed" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/0/4/041208fbc335dc0a3bab382328c1d66eb7723aed_2_690x493.png" alt="image" data-base62-sha1="A0y5LxSwurYjR170UsJifiGPdb" width="690" height="493" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/0/4/041208fbc335dc0a3bab382328c1d66eb7723aed_2_690x493.png, https://discuss.pytorch.org/uploads/default/optimized/3X/0/4/041208fbc335dc0a3bab382328c1d66eb7723aed_2_1035x739.png 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/0/4/041208fbc335dc0a3bab382328c1d66eb7723aed.png 2x" data-dominant-color="F5F7F9"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">image</span><span class="informations">1351×966 48.8 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div><br>
that grey arrow shows the concatenate action.</p>
<p>I think this is the reason why you can get ouput from strange shape input.</p>
<p>sorry about my poor english <img src="https://discuss.pytorch.org/images/emoji/apple/frowning.png?v=12" title=":frowning:" class="emoji" alt=":frowning:" loading="lazy" width="20" height="20"></p>

Thierry_Roger_Bayala: <p>No problem I understood perfectly. Probably I need to explain more deeply my problem. I have paired images (input, target) datasets and my purpose is to train a Network using  these datasets so that given an input image, I can applied the weight to produce the output. I have defined the Network as a function as follow:</p>
<p>def Unet():</p>
<pre><code>layer =[
        nn.Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False),
        nn.BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
        nn.ReLU(inplace=True)
]

layer += [nn.Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
        nn.BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
        nn.ReLU(inplace=True)]


layer += [
    nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),
    
    nn.Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
    nn.BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
    nn.ReLU(inplace=True),

    nn.Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
    nn.BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
    nn.ReLU(inplace=True)
] 





layer += [
    nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),
    
    nn.Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
    nn.BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
    nn.ReLU(inplace=True),

    nn.Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
    nn.BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
    nn.ReLU(inplace=True)
] 




layer += [
    nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),
    
    nn.Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
    nn.BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
    nn.ReLU(inplace=True),

    nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
    nn.BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
    nn.ReLU(inplace=True)
] 


layer += [
    nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),
    
    nn.Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
    nn.BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
    nn.ReLU(inplace=True),
    nn.Conv2d(1024, 1024, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
    nn.BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
    nn.ReLU(inplace=True)
] 



layer += [ 
        nn.ConvTranspose2d(1024, 1024, kernel_size=(2, 2), stride=(2, 2)),
        
        nn.Conv2d(1024, 512, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
        nn.BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
        nn.ReLU(inplace=True),

        nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
        nn.BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
        nn.ReLU(inplace=True)
] 




layer += [ 
        nn.ConvTranspose2d(512, 512, kernel_size=(2, 2), stride=(2, 2)),
        
        nn.Conv2d(512, 256, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
        nn.BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
        nn.ReLU(inplace=True),

        nn.Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
        nn.BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
        nn.ReLU(inplace=True)
] 





layer += [ 
        nn.ConvTranspose2d(256, 256, kernel_size=(2, 2), stride=(2, 2)),
        
        nn.Conv2d(256, 128, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
        nn.BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
        nn.ReLU(inplace=True),

        nn.Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
        nn.BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
        nn.ReLU(inplace=True)
] 




layer += [ 
        nn.ConvTranspose2d(128, 128, kernel_size=(2, 2), stride=(2, 2)),
        
        nn.Conv2d(128, 64, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
        nn.BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
        nn.ReLU(inplace=True),

        nn.Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1),padding=(1, 1), bias=False),
        nn.BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True),
        nn.ReLU(inplace=True)
] 


layer += [nn.Conv2d(64, 3, kernel_size=(1, 1), stride=(1, 1), padding=0)]

net = nn.Sequential(*layer)

return net
</code></pre>
<p>For example : input shape [1, 3, 64, 95] and target shape is [1, 3, 64, 95]</p>
<p>When the input pass through the Net the Output a tensor shape of [1, 3, 64, 80]. The loss calculation MSE produced an error since the output and the target have differents shape</p>
<p>My forward is computed as follow:</p>
<p>config.model = Unet()<br>
def forward(imgs, config):<br>
x, y = imgs[0], imgs[1]<br>
device = torch.device(‘cpu’)<br>
x,y=x.to(device), y.to(device)<br>
return config.model(Variable(x)), y<br>
config.forward = forward<br>
run(config)</p>

QLYYLQ: <p>I know that, you can see my above reply. The problem in your code are functions like this : <code>nn.ConvTranspose2d(128, 128, kernel_size=(2, 2), stride=(2, 2))</code>, you should set it to 128,56 instead of 128,128.(see my code in above reply)</p>
<p>After i remove the <code>torch.cat</code> function, don’t half the upsample channel in my code, i get the same output shape([80,64]), you can see the wrong code:</p>
<pre data-code-wrap="python"><code class="lang-python">class UNet(nn.Module):
    def __init__(self, in_channels=3, out_channels=1):
        super().__init__()
        
        # encoder part
        self.enc1 = DoubleConv(in_channels, 64)
        self.enc2 = DoubleConv(64, 128)
        self.enc3 = DoubleConv(128, 256)
        self.enc4 = DoubleConv(256, 512)
        
        # polling layer
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        
        # bottle neck
        self.bottleneck = DoubleConv(512, 1024)
        
        # up sampling part
        self.up1 = nn.ConvTranspose2d(1024, 1024, kernel_size=2, stride=2)
        self.up2 = nn.ConvTranspose2d(512, 512, kernel_size=2, stride=2)
        self.up3 = nn.ConvTranspose2d(256, 256, kernel_size=2, stride=2)
        self.up4 = nn.ConvTranspose2d(128, 128, kernel_size=2, stride=2)
        
        # decoder part
        self.dec1 = DoubleConv(1024, 512)
        self.dec2 = DoubleConv(512, 256)
        self.dec3 = DoubleConv(256, 128)
        self.dec4 = DoubleConv(128, 64)
        
        # output layer
        self.out = nn.Conv2d(64, out_channels, kernel_size=1)

    def forward(self, x):
        # encoder
        enc1 = self.enc1(x)
        enc2 = self.enc2(self.pool(enc1))
        enc3 = self.enc3(self.pool(enc2))
        enc4 = self.enc4(self.pool(enc3))
        
        # bottleneck
        bottleneck = self.bottleneck(self.pool(enc4))
        
        # decoder
        dec1 = self.dec1(self.up1(bottleneck))
        dec2 = self.dec2(self.up2(dec1))
        dec3 = self.dec3(self.up3(dec2))
        dec4 = self.dec4(self.up4(dec3))
        
        return self.out(dec4)
</code></pre>
<p>You can compare the different between this code and the architecture about U-Net.</p>
<p>Also, you can see correct code with concatenate action.</p>

Thierry_Roger_Bayala: <p>I use exactly the above code but I am getting this error now</p>
<p>File “xxxx/model/Unet.py”, line 61, in forward<br>
dec1 = self.dec1(torch.cat([self.up1(bottleneck), enc4], dim=1))<br>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^<br>
RuntimeError: Sizes of tensors must match except in dimension 1. Expected size 10 but got size 11 for tensor number 1 in the list</p>

QLYYLQ: <p>Yes, because you put a tensor with odd height or width. This code of U-Net just support the size is a multiple of 16 of the width or height(96 and 64 is suitable). If you want other width, just using dynamic padding.</p>

Thierry_Roger_Bayala: <p>Yes you are right because I can produce the same error if I replace the heigh 96 → 95. Could you please help me on how can use dynamic padding ?</p>

QLYYLQ: <p>Sorry, i had an exam just now. You can add a function in unet for dynamic padding, i will give the total code</p>
<pre data-code-wrap="python"><code class="lang-python">import torch
import torch.nn as nn
import torch.nn.functional as F


class DoubleConv(nn.Module):
    def __init__(self, in_channels, out_channels):
        super().__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True)
        )

    def forward(self, x):
        return self.conv(x)


def dynamic_padding(x1, x2):
    # calculate the difference in shape
    diff_h = x2.size()[2] - x1.size()[2]
    diff_w = x2.size()[3] - x1.size()[3]
    
    # calculate the padding
    pad_h1 = diff_h // 2
    pad_h2 = diff_h - pad_h1
    pad_w1 = diff_w // 2
    pad_w2 = diff_w - pad_w1
    
    # apply padding
    x1 = F.pad(x1, [pad_w1, pad_w2, pad_h1, pad_h2])
    
    return x1


class UNet(nn.Module):
    def __init__(self, in_channels=3, out_channels=1):
        super().__init__()
        
        # encoder part
        self.enc1 = DoubleConv(in_channels, 64)
        self.enc2 = DoubleConv(64, 128)
        self.enc3 = DoubleConv(128, 256)
        self.enc4 = DoubleConv(256, 512)
        
        # polling layer
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        
        # bottle neck
        self.bottleneck = DoubleConv(512, 1024)
        
        # up sampling part
        self.up1 = nn.ConvTranspose2d(1024, 512, kernel_size=2, stride=2)
        self.up2 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2)
        self.up3 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2)
        self.up4 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2)
        
        # decoder part
        self.dec1 = DoubleConv(1024, 512)
        self.dec2 = DoubleConv(512, 256)
        self.dec3 = DoubleConv(256, 128)
        self.dec4 = DoubleConv(128, 64)
        
        # output layer
        self.out = nn.Conv2d(64, out_channels, kernel_size=1)
    @staticmethod
    def dynamic_upsample(x1, x2):
        upsample = dynamic_padding(x1, x2)
        return torch.cat([upsample,x2], dim=1)
    def forward(self, x):
        # encoder
        enc1 = self.enc1(x)
        enc2 = self.enc2(self.pool(enc1))
        enc3 = self.enc3(self.pool(enc2))
        enc4 = self.enc4(self.pool(enc3))
        
        # bottleneck
        bottleneck = self.bottleneck(self.pool(enc4))
        
        # decoder
        dec1 = self.dec1(self.dynamic_upsample(self.up1(bottleneck), enc4))
        dec2 = self.dec2(self.dynamic_upsample(self.up2(dec1), enc3))
        dec3 = self.dec3(self.dynamic_upsample(self.up3(dec2), enc2))
        dec4 = self.dec4(self.dynamic_upsample(self.up4(dec3), enc1))
        
        return self.out(dec4)


if __name__ == "__main__":
    # create a model

    test_size = [(1, 3, 93, 64), (1, 3, 81, 93), (1, 3, 198, 108)]
    model = UNet(in_channels=3, out_channels=1)
    for size in test_size:
        x = torch.randn(size)
        output = model(x)
        print(f"Input shape: {x.shape}")
        print(f"Output shape: {output.shape}")
        print()
</code></pre>
<p>I write a easy test for this dynamic padding, you can check it too.  Also, you can choose a different padding strategy which is customized for your datasets by replacing the <code>F.pad</code> or setting it with <code>nearest</code> and so on.</p>

Thierry_Roger_Bayala: <aside class="quote no-group" data-username="QLYYLQ" data-post="12" data-topic="214768">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/qlyylq/48/74718_2.png" class="avatar"> QLYYLQ:</div>
<blockquote>
<p><code>dynamic_upsample</code></p>
</blockquote>
</aside>
<p>Thank you very much. The problem is now solved from your code</p>