Changing the weights of Conv2d


#1

So I am trying to do filtering via Conv2d, I define my kernel and then change the weights of Conv2d and thought that should be it, but the results does not match

For a toy example, I define a 3x3 kernel : [[0, 0, 0],[0, 1, 0],[0, 0, 0]], the output results of using this kernel should basically give me identical results as an input. but I am not sure why it is not happening like that:

Here is the whole toy code:

import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F
import torch

Input = torch.rand(1,2,6,6)

Guass = nn.Conv2d(Input.size(1), Input.size(1), 3, padding = 1)
KernelGauss = torch.ones(3,3)*0.
KernelGauss[1,1] = 1.
KernelGaussExpand = KernelGauss.expand(Guass.weight.size())
Guass.weight = torch.nn.Parameter(KernelGaussExpand, requires_grad=False)

OutPut = Guass(Input)

print('KernelGauss: {}' .format(KernelGauss))
print('Input: {}' .format(Input))
print('OutPut: {}' .format(OutPut))
KernelGauss: tensor([[0., 0., 0.],
        [0., 1., 0.],
        [0., 0., 0.]])
Input: tensor([[[[0.1694, 0.0436, 0.7638, 0.4422, 0.6436, 0.1260],
          [0.2136, 0.2536, 0.1094, 0.6026, 0.2102, 0.8117],
          [0.6218, 0.5365, 0.9977, 0.4297, 0.4261, 0.7260],
          [0.8062, 0.3274, 0.4722, 0.2773, 0.4304, 0.7448],
          [0.6605, 0.8976, 0.7353, 0.7233, 0.9757, 0.2564],
          [0.6651, 0.2333, 0.2524, 0.8768, 0.0754, 0.4961]],

         [[0.8020, 0.6601, 0.4271, 0.3141, 0.6387, 0.8583],
          [0.3664, 0.9589, 0.7841, 0.6330, 0.0851, 0.4114],
          [0.4414, 0.9218, 0.1864, 0.5323, 0.4601, 0.4648],
          [0.0841, 0.8478, 0.8975, 0.1383, 0.0706, 0.0810],
          [0.8904, 0.7208, 0.2150, 0.0034, 0.4385, 0.7455],
          [0.8900, 0.6735, 0.5207, 0.4046, 0.6463, 0.9222]]]])
OutPut: tensor([[[[1.1774, 0.9097, 1.3969, 0.9623, 1.4883, 1.1903],
          [0.7860, 1.4185, 1.0995, 1.4416, 0.5013, 1.4290],
          [1.2692, 1.6643, 1.3901, 1.1680, 1.0922, 1.3967],
          [1.0962, 1.3812, 1.5756, 0.6216, 0.7070, 1.0318],
          [1.7568, 1.8244, 1.1563, 0.9327, 1.6201, 1.2078],
          [1.7611, 1.1128, 0.9791, 1.4874, 0.9277, 1.6242]],

         [[1.0561, 0.7884, 1.2756, 0.8410, 1.3670, 1.0690],
          [0.6647, 1.2972, 0.9782, 1.3203, 0.3800, 1.3077],
          [1.1479, 1.5430, 1.2688, 1.0467, 0.9709, 1.2754],
          [0.9749, 1.2599, 1.4543, 0.5003, 0.5857, 0.9105],
          [1.6355, 1.7031, 1.0349, 0.8114, 1.4988, 1.0865],
          [1.6398, 0.9915, 0.8578, 1.3661, 0.8064, 1.5029]]]],
       grad_fn=<ThnnConv2DBackward>)

(Arul) #2

Did you forget about the bias?


(Justus Schock) #3

You forgot to deactivate the bias term (which is True by default)

Edit: @InnovArul was a few seconds faster, so nvm :slight_smile:


#4

how should i deactivate it?


(Justus Schock) #5
Guass = nn.Conv2d(Input.size(1), Input.size(1), 3, padding = 1, bias=False)

Also note your typo in the layers name.


(Arul) #6

nn.Conv2d(Input.size(1), Input.size(1), 3, padding = 1, bias=False)

@justusschock :slight_smile:


#7

@InnovArul @justusschock
I deactivated it, but it is still not giving the answer it should…

Update:
It is a little wierd…
When i do
Input = torch.rand(1,1,6,6)
it works

but when i do:
Input = torch.rand(1,2,6,6)
it doesnot


(Arul) #8

Ok. well, you are having 2 channels (which I didn’t notice). The conv layer will multiply the kernel with input and add up the results for every position.

Try having only one channel and check the results.


#9

yeah exactly!
I just noticed that…

Do you know what i should do to make it work for batchsize and channel size more than 1?


(Arul) #10

you can use group convolutions.

Guass = nn.Conv2d(Input.size(1), Input.size(1), 3, padding = 1, bias=False, groups=Input.size(1))


#11

I have never used that before! but it gives what i want!!
Thank you :slight_smile:


(Justus Schock) #12

and you could also use the functional API which removes the necessarity to change the weigthts by hand since you could simply pass the weights to the function.


#13

hmmm what do you mean? :thinking:


(Justus Schock) #14
x = torch.rand(1, 1, 64, 64)
gauss_kernel = torch.Tensor([[0, 0, 0], [0, 1, 0], [0, 0, 0]]).unsqueeze(0).unsqueeze(0)
out = F.conv2d(x, gauss_kernel, padding=1)
print(x)
print(gauss_kernel)
print(out)
tensor([[[[0.7888, 0.7222, 0.9251,  ..., 0.1763, 0.8585, 0.7747],
          [0.8203, 0.2307, 0.4474,  ..., 0.8498, 0.3399, 0.2610],
          [0.0001, 0.2678, 0.2113,  ..., 0.9698, 0.3422, 0.1166],
          ...,
          [0.7921, 0.1250, 0.1268,  ..., 0.8102, 0.1775, 0.4617],
          [0.1761, 0.6137, 0.6097,  ..., 0.0786, 0.8547, 0.4948],
          [0.7365, 0.6266, 0.6305,  ..., 0.6367, 0.0811, 0.8240]]]])
tensor([[[[0., 0., 0.],
          [0., 1., 0.],
          [0., 0., 0.]]]])
tensor([[[[0.7888, 0.7222, 0.9251,  ..., 0.1763, 0.8585, 0.7747],
          [0.8203, 0.2307, 0.4474,  ..., 0.8498, 0.3399, 0.2610],
          [0.0001, 0.2678, 0.2113,  ..., 0.9698, 0.3422, 0.1166],
          ...,
          [0.7921, 0.1250, 0.1268,  ..., 0.8102, 0.1775, 0.4617],
          [0.1761, 0.6137, 0.6097,  ..., 0.0786, 0.8547, 0.4948],
          [0.7365, 0.6266, 0.6305,  ..., 0.6367, 0.0811, 

This way you don’t have to wrap your kernel into a Parameter and you don’t have to modify the weights by hand, it might also reduce some memory (which really is not that relevant in this small example).