Image convolution return wrong output dimension

username: Ettore_Celozzi
cooked: <p>Hello, I’m new to Pytorch. I’m tring to convert a code that use functions from scipy and numpy library in Pytorch in order to build a NN and execute it on the GPU.</p>
<p>I have some convolution layers that perform the convolution between a gaussian filter and an image. Exploiting the separability of the gaussian filters I perform the convolution along the x-axis and then on the y-axis.</p>
<p>The code without PyTorch is:</p>
<pre><code class="lang-auto">from scipy.ndimage.filters import convolve

img_convolved = convolve(convolve(img, gy[:, None]), gx[None, :])
# default padding mode is 'reflect'
</code></pre>
<p>where <em>gx</em> and <em>gy</em> are the 1D gaussian filters.</p>
<p>Mine “translation” to PyTorch is:</p>
<pre><code class="lang-auto">import torch
import torch.nn.functional as F
import numpy as np

img = np.random.rand(512, 512) # random image with shape
pad_w, pad_h = int(np.ceil(img.shape[0] / gx.size()[0])), int(np.ceil(img.shape[1] / gx.size()[0]))

img = torch.from_numpy(img).repeat(1, 1, 1, 1)
gx, gy = torch.flip(gx, (0,)).type(torch.float32), \
         torch.flip(gy, (0,)).type(torch.float32)
gx, gy = gx.repeat(1, 1, 1, 1), gy.repeat(1, 1, 1).unsqueeze(3)
img = F.pad(img, [0, 0, pad_w, pad_h], 'reflect')

convY = F.conv2d(img.float(), gy, stride=1)
convX = F.conv2d(convY, gx, stride=1)
</code></pre>
<p>To notice that the dimension of the gaussian filters change based on the value of the <strong>sigma</strong> chosen (this will be an hyperparameter to optimize later). Some examples are 47,5,4,…</p>
<p>My problems here are:</p>
<ol>
<li>
<p>The final output of the convolution (<em>convX</em>) has the shape that depends on the filters shape. What I want is an image with the same shape of the original image (512,512). This is the output of the scipy convolve method, but not the one of the PyTorch convolution.</p>
</li>
<li>
<p>Will I be able to run this on the GPU building a Convolutional layer?</p>
</li>
</ol>

username: albanD
cooked: <p>Hi,</p>
<p>The convolution will not ensure that the output is of the same size indeed.<br>
But if you use stride=1, no dilation and your kernel has an odd size, you can set the padding to be <code>floor(kern/2)</code> to make sure that the output will have the same size as the input.</p>
<p>And yes these ops are all implemented on GPU so you will be able tto use it.</p>

username: Ettore_Celozzi
cooked: <p>Hi, thank you for the answer.<br>
The result of the first convolution has the desired shape, but the last one (along x-axis) change the dimension of the columns.<br>
Any ideas?<br>
These are my new padding dimensions:</p>
<pre><code class="lang-auto">pad_w, pad_h = int(np.floor(gx.size()[0] / 2)), int(np.floor(gx.size()[0] / 2))
</code></pre>

username: albanD
cooked: <p>I simplified your code below:</p>
<pre><code class="lang-python">import torch
import torch.nn.functional as F
import numpy as np

img = torch.rand(1, 1, 512, 512)

kx, ky = 5, 5

# Goes from 1 channel to 1 channel
weight_h = torch.rand(1, 1, ky, 1)
weight_w = torch.rand(1, 1, 1, kx)

padx = kx // 2
pady = ky // 2

convY = F.conv2d(img, weight_h, padding=(pady, 0))
convX = F.conv2d(convY, weight_w, padding=(0, padx))

print(img.size())
print(convY.size())
print(convX.size())
</code></pre>

username: Ettore_Celozzi
cooked: <p>Thank you very much!! You saved me a lot of time.<br>
By the way I’ve noticed that plotting the resulting image the last column and the first one are cut. I can’t understand why.</p>
<p>Edit: Ok I figured out the bug. It was in another part of the code.</p>