Convolution operation without the final summation

username: Saeed_Izadi1
cooked: <p>Hello</p>
<p>Is there any way to perform a vanilla convolution operation but without the function summation? Assume that we a feature map, X, of size [B, 3, 64, 64] and a single kernel of size [1, 3, 3, 3]. When doing the vanilla convolution, we get a feature map of size [B, 1, 62, 62], while I’m after a way to get a feature map of size [B, 3, 62, 62], just before collapsing/summing all the convolutional channels into a single feature map</p>
<p>Thanks</p>

username: ptrblck
cooked: <p>How would you like to perform the reduction of each step?<br>
Generally, you could <code>unfold</code> the input into <code>3x3x3</code> patches, perform the multiplication with the kernel, (sum the result), and <code>fold/reshape</code> to the output shape. Since you are not performing the sum, you would have overlapping patches and I’m not sure how you would like to reduce/reshape them back.</p>

username: Saeed_Izadi1
cooked: <p>Thanks for the reply.</p>
<p>I want to avoid the reduction across the channels and not the spatial multiplication.<br>
So, each kernel of size 3x3x3 gives three feature maps, instead of merging them to form a single feature map in the output.</p>

username: ptrblck
cooked: <p>In that case, the <a href="https://pytorch.org/docs/stable/nn.html#torch.nn.Conv2d" rel="nofollow noopener"><code>groups</code></a> argument should yield the expected results using <code>groups=in_channels</code>:</p>
<pre><code class="lang-python">conv = nn.Conv2d(3, 3, 3, groups=3)
x = torch.randn(10, 3, 64, 64)
output = conv(x)
</code></pre>

username: Saeed_Izadi1
cooked: <p>I’m already familiar with this option but using <code>groups</code> is not actually what I need.</p>
<p>The operation you wrote is just performing convolution with a single kernel 3x3x3 kernel while I need the same operation for say 32 different kernels.</p>
<p>It’s a bit hard to explain what I am after.</p>
<p>Thanks for the time</p>

username: phan_phan
cooked: <p>Try to give an example with simple tensors and simple kernels, along with the expected results, so we can see what you want to do.</p>

username: DavidWRomero
cooked: <p>Hi <a class="mention" href="/u/saeed_izadi1">@Saeed_Izadi1</a>, did you find a solution to this problem?</p>
<p><a class="mention" href="/u/ptrblck">@ptrblck</a> What Saeed was after is the following:<br>
A normal convolution between a [Bx3x5x5] input and a [1x3x3x3] kernel would produce a [Bx1x4x4] response. The reason for that is that after performing spatial convolution channel-wise, i.e. along the last 2 indices ( and producing a tensor [Bx1x3x4x4] ), the channel-wise responses are summed up into a single channel and thus convolution produces a tensor [Bx1x4x4]. Is there a way to obtain access to the tensor [Bx1x3x4x4] ?</p>
<p>Thanks a lot! <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>
<p>Regards,<br>
David</p>

username: ptrblck
cooked: <p>Wouldn’t my code snippet yield exactly this? <img src="https://discuss.pytorch.org/images/emoji/apple/thinking.png?v=9" title=":thinking:" class="emoji" alt=":thinking:"><br>
Have a look at this comparison with a manual approach, where each kernel is used on a single input channel:</p>
<pre><code class="lang-python"># Grouped approach
conv = nn.Conv2d(3, 3, 3, groups=3, bias=False)
x = torch.randn(10, 3, 64, 64)
output = conv(x)

# Compare with manual approach
kernels = conv.weight
output_manual = []
for idx in range(3):
    kernel = kernels[idx:idx+1]
    input = x[:, idx:idx+1]
    out = F.conv2d(input, kernel)
    output_manual.append(out)
output_manual = torch.cat(output_manual, dim=1)

print((output_manual - output).abs().max())
&gt; tensor(4.7684e-07, grad_fn=&lt;MaxBackward1&gt;)
</code></pre>
<p>Let me know, if I still misunderstand the use case. <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>

username: DavidWRomero
cooked: <p>Hi <a class="mention" href="/u/ptrblck">@ptrblck</a> sorry about the confusion, you are completely right! That is exactly what your proposed approach does.<br>
Thanks for your fast reply <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>
<p>Best Regards and Happy New Year,<br>
David</p>

username: xyang35
cooked: <p>If I understand <a class="mention" href="/u/saeed_izadi1">@Saeed_Izadi1</a> correctly, I think the correct way to achieve that should be something like:</p>
<blockquote>
<p>conv = nn.Conv2d(3, 9, 3, groups=3)</p>
</blockquote>