we get all the windows using unfold right?. So, I will try to remove the windows whose center is not in the interested region so that in matrix multiplication I will have a matrix of lesser size. which leads to an increase in the speedup. If I am wrong please correct me.
I have written the below code for normal convolution from scratch using previous discussions in this thread. And I am thinking if I am able to decrease the number of windows created then I would be able to decrease the running time of matrix multiplication. Please correct me if I am wrong
import cv2
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import torch
import torch.nn as nn
class Myconv2d(torch.autograd.Function):
@staticmethod
def forward(ctx, input, weight, bias=None):
ctx.save_for_backward(input, weight, bias)
#required variables
batch_size, channels , h, w = input.shape
kh, kw = weight.shape # kernel size
dh, dw = 1, 1 # stride
ph, pw = 0, 0 # padding
#create all windows, final size of patches : (batch_size*windows per batch , kh*kw*channels)
patches = image.unfold(2, kh, dh).unfold(3, kw, dw)
patches = patches.contiguous().view(batch_size, channels, -1, kh, kw)
patches = patches.permute(0, 2, 1, 3, 4)
patches = patches.view(-1, channels, kh, kw)
windows = patches.shape[0]
patches = torch.reshape(patches, (windows,-1))
#flatten the weight
filters = weight.contiguous().view((-1,))
#matrix multiplication
patches = filters @ patches.T
#output size calculation
oh = (int)((h-kh+2*ph)/dh+1)
ow = (int)((w-kw+2*pw)/dw+1)
#back to normal image view
patches = patches.reshape(batch_size,channels, oh,ow)
return patches
@staticmethod
def backward(ctx, grad_output):
input, weight, bias = ctx.saved_tensors
grad_input = grad_weight = grad_bias = None
if ctx.needs_input_grad[0]:
grad_input = grad_output.mm(weight)
if ctx.needs_input_grad[1]:
grad_weight = grad_output.t().mm(input)
if bias is not None and ctx.needs_input_grad[2]:
grad_bias = grad_output.sum(0).squeeze(0)
return grad_input, grad_weight, grad_bias
#model
class Myconv2D(torch.nn.Module):
def __init__(self, input_features, output_features, bias = None):
super(Myconv2D, self).__init__()
self.input_features = input_features
self.output_features = output_features
sobel = torch.tensor([ [ 1.0, 6, 15, 20, 15, 6, 1],
[ 2, 12, 30, 40, 30, 12, 2],
[ 3, 18, 45, 60, 45, 18, 3],
[ 0, 0, 0, 0, 0, 0, 0],
[ -3, -18,-45,-60,-45,-18, -3],
[ -2, -12, -30,-40,-30,-12, -2],
[ -1, -6, -15, -20, -15, -6, -1] ])
self.weight = nn.Parameter(sobel)
if bias:
self.bias = nn.Parameter(torch.empty(output_features))
else:
self.register_parameter('bias', None)
if self.bias is not None:
self.bias.data.uniform_(-0.1, 0.1)
def forward(self, input):
return Myconv2d.apply(input, self.weight, self.bias)
if __name__ == "__main__":
path = "../input/motorroll-tracking/0001.jpg"
img = cv2.imread(path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
batch_size = 1
channels = 1
h, w = img.shape
image = torch.from_numpy(img/255.0).float() # input image
image = image.reshape(batch_size,channels,h,w)
mymodel = Myconv2D(1,1)
output = mymodel.forward(image)
for i in range(batch_size):
plt.imshow(output[i,0,:,:].detach().numpy(),cmap='gray')