Error when do depthwise conv2d

Weixuan_Sun: <p>My problem is a little bit weird, I am trying to use depthwise convolutional to simultaneously do a Sobel filter on every channel of a tensor. When I do it on a single layer tensor, it works all good. The code is as follow:</p>
<pre><code class="lang-auto">input_img = torch.FloatTensor(input_image)  # 1080*1080
input_img=input_img.unsqueeze(0).unsqueeze(0)  # 1*1*1080*1080

a = torch.Tensor([[[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]]])
x = Variable(input_img.float(), requires_grad=False)
w = Variable(a.float(), requires_grad=False)
w = w.unsqueeze(1)

gx = F.conv2d(x, w, padding=1, groups=1)
gx = torch.relu(torch.tanh(gx))
gx = gx.squeeze(0)
</code></pre>
<p>Input image is image1, output is the second image.</p>
<p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/2X/0/0296370d5018677633e11740183184f2198f29db.png" data-download-href="https://discuss.pytorch.org/uploads/default/0296370d5018677633e11740183184f2198f29db" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/2X/0/0296370d5018677633e11740183184f2198f29db_2_690x230.png" alt="image" data-base62-sha1="mSMVFaaQVDLm7fOzwIrOsmYQoX" width="690" height="230" srcset="https://discuss.pytorch.org/uploads/default/optimized/2X/0/0296370d5018677633e11740183184f2198f29db_2_690x230.png, https://discuss.pytorch.org/uploads/default/optimized/2X/0/0296370d5018677633e11740183184f2198f29db_2_1035x345.png 1.5x, https://discuss.pytorch.org/uploads/default/original/2X/0/0296370d5018677633e11740183184f2198f29db.png 2x" data-dominant-color="060606"><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">1095×365 8.05 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></p>
<p>However, when it comes to multi-channel tensor, I put the above input image to the first channel of the input tensor and set groups=5, the code is as follow:</p>
<pre><code class="lang-auto">input_img = torch.FloatTensor(multi_channel_input) # 5*1080*1080
input_img=input_img.unsqueeze(0)  #1*5*1080*1080
a = torch.Tensor([[[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
                  [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
                  [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
                  [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
                  [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]])

x = Variable(input_img.float(), requires_grad=False)
w = Variable(a.float(), requires_grad=False)
w = w.unsqueeze(1)

gx = F.conv2d(x, w, padding=1, groups=5)
gx = torch.relu(torch.tanh(gx))
</code></pre>
<p>I expect every sobel kernel works independently on every channel of input tensor just like depthwise conv. And the output of the first channel should be no difference to the above single channel one, but the actual output is the third image,  obviously, the second one looks more correct.</p>
<p>I wonder did I create depthwise conv2d wrongly? Or did I make any mistake?</p>

ptrblck: <p>Your code seems to work on this dummy example:</p>
<pre><code class="lang-python">input_img = torch.zeros(5, 100, 100)
input_img[:, 25:75, 25:75] = 1.
input_img = input_img.unsqueeze(0)

a = torch.tensor([[[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
                  [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
                  [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
                  [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]],
                  [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]]).float()

x = input_img
w = a
w = w.unsqueeze(1)
gx = F.conv2d(x, w, padding=1, groups=5)

f, axarr = plt.subplots(5)
for idx in range(5):
    axarr[idx].imshow(gx[0, idx].numpy())
</code></pre>

Weixuan_Sun: <p>Thank you very much, it works. I found I just made a mistake on the input image.<br>
btw, I wonder is there any way to simultaneously implement a fixed size conv filter on every channel of the input rather than copy the filter by 5 times like I did in my code?</p>

ptrblck: <p><code>expand(5, -1, -1, -1)</code> or <code>repeat(5, 1, 1, 1)</code> should work:</p>
<pre><code class="lang-python">gx = F.conv2d(x, w.expand(5, -1, -1, -1), padding=1, groups=5)
</code></pre>
<p>If you want to manipulate <code>w</code> inplace, you should use <code>repeat</code>, since it will allocate new memory, while <code>expand</code> uses the same memory and just changes the stride and size.</p>