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')