How to create a novel convolution kernel?

lidehui: <p>We can use <code>torch.nn.Conv2d</code> to create an usual convolution layer, but if I want to creat a convolution layer with a kernel of novel shape, such as ‘T’ shape(means with kernel weight of [w1 w2 w3; 0 w4 0; 0 w5 0] ), what should I do?<br>
Could somebody help me? Thanks very much!</p>

InnovArul: <p>you can make use of <a href="https://pytorch.org/docs/stable/nn.html#torch.nn.functional.conv2d">torch.nn.functional.conv2d()</a>.</p>
<pre><code class="lang-auto">import torch.nn.functional as F
kernel = torch.Tensor([[[[1,2,3], [0,4,0], [0,5,0]]]])
data = torch.randn(1,1,10,10)
output = F.conv2d(data, kernel)
</code></pre>

lidehui: <p>Thanks for your answer! But I want to train the layer in a network, means w1 to w5 are learnable. Just like dilate convolution, some weights are 0, and others are learnable. Do you know how to do this?</p>

Florian_1990: <p>If you initialize your kernel with zeros in the right places, you could probably use <a href="https://pytorch.org/docs/stable/autograd.html#torch.Tensor.register_hook" rel="nofollow noopener"><code>register_hook</code></a> to zero the corresponding gradients to avoid learning those parameters.</p>

Naman-ntc: <p>you can still use function approach</p>
<pre><code class="lang-auto">class NovelConv(nn.Module):
    def __init__(self):
        self.W = nn.Parameter(torch.Tensor([[w1,w2,w3],[w4,0,0],[w5,0,0]]))
    def forward(self,x):
        return F.conv2d(x, self.W)
</code></pre>
<p>Backpropogation will work by doing this</p>

lidehui: <p>Thank you! As far as I know, register_hook is used to get intermediate results. How to use register_hook to zero the gradients, could you please explain it more specifically?</p>

lidehui: <p>Thank you! In this way, I need to extract w1 to w5 from original layer, and give it to W, how to do this?</p>

1435b992edc81c3b31ba: <p>thank you! I used your function .but have the NameError: name ‘w1’ is not defined.how to solve it ?</p>

1435b992edc81c3b31ba: <p>do you solve this question?I meet the same question</p>

Alberto_Albiol: <p>I found a solution for a problem similar that yours. Check the code below for a convolution block with symmetric coefficients</p>
<p>I initially tried to create the weight matrix as <a class="mention" href="/u/naman-ntc">@Naman-ntc</a> but the graph was broken and the gradients did not flow to the scalar variables</p>
<p>For this reason I create the weight matrix by summing the coefficients to a zero matrix. Any other simpler alternatives are welcome</p>
<pre><code class="lang-auto">class Conv2d_symmetric(nn.Module):
    def __init__(self):
        super(Conv2d_simple, self).__init__()

        self.a = nn.Parameter(torch.randn(1))
        self.b = nn.Parameter(torch.randn(1))
        self.c = nn.Parameter(torch.randn(1))


        self.bias = None
        self.stride = 2
        self.padding = 1
        self.dilation = 1
        self.groups = 1



    def forward(self, input):

        #in case we use gpu we need to create the weight matrix there
        device = self.a.device

        weight = torch.zeros((1,1,3,3)).to(device)
        weight[0,0,0,0] += self.c[0]
        weight[0,0,0,1] += self.b[0]
        weight[0,0,0,2] += self.c[0]
        weight[0,0,1,0] += self.b[0]
        weight[0,0,1,1] += self.a[0]
        weight[0,0,1,2] += self.b[0]
        weight[0,0,2,0] += self.c[0]
        weight[0,0,2,1] += self.b[0]
        weight[0,0,2,2] += self.c[0]


        # print("weight= ", weight)
        # print("inout = ", input)
        return F.conv2d(input, weight, self.bias, self.stride,
                        self.padding, self.dilation, self.groups)
</code></pre>