You cant prevent the weights from changing during gradient descent. However, you can introduce a parameter called mask, which multiplies a mask with the weights, and use that to do the forward pass and the backward pass.
After this, you can use m.mask.shape, etc,. to look at the profile of the masked weights in your sparse network.
Here is my implementation:
class newlinear(Function):
    def __init__(self,mask):
        super(newlinear, self).__init__()
        self.mask = mask

     #extendWeights is the masked weight which is used in the forward and backprop. 
     #Hence, the sparsity is maintained during backprop
    def forward(self, input, weight):
        self.save_for_backward(input, weight)
        extendWeights = weight.clone()
        extendWeights.mul_(self.mask.data)
        output = input.mm(extendWeights.t())
        return output

    def backward(self, grad_output):
        input, weight = self.saved_tensors
        grad_input = grad_weight  = None
        extendWeights = weight.clone()
        extendWeights.mul_(self.mask.data)

        if self.needs_input_grad[0]:
            grad_input = grad_output.mm(extendWeights)
        if self.needs_input_grad[1]:
            grad_weight = grad_output.clone().t().mm(input)
            grad_weight.mul_(self.mask.data)

        return grad_input, grad_weight

 ###############################################################
     
class NewLinear(torch.nn.Module):
    def __init__(self, input_features, output_features,matrix, mode='random'):
        super(NewLinear, self).__init__()
        self.input_features = input_features
        self.output_features = output_features
        self.matrix = matrix

        self.weight = nn.Parameter(data=torch.Tensor(output_features, input_features), requires_grad=True)
        
        '''**********************************Getting the mask**************************************'''

        ##Use your definition of mask here
        self.mask = np.random.randint(2,size=(output_features,input_features))
        kk += self.input_features
        self.mask =  torch.from_numpy(self.mask).cuda()
        
        
        nn.init.kaiming_normal(self.weight.data,mode='fan_in')
        '''Declaring the mask as a parameter'''
        self.mask =  nn.Parameter(self.mask.cuda())
        self.mask.requires_grad = False

    def forward(self, input):
        return newlinear(self.mask)(input, self.weight)