I wrote a short piece of code in order to determinate whether the padding within Conv2D is done before or after the convolution:
import torch.nn as nn
import numpy as np
import torch

weights = np.array([[1, 2, 6],
                    [4, 7, 9],
                    [1, 4, 7]])

class Model1(nn.Sequential):
    def __init__(self):
        super(Model1, self).__init__()
        self.add_module('conv', nn.Conv2d(1, 1, kernel_size=3, padding=1, bias=False))
        
        self.conv.weight.data = torch.from_numpy(weights).view(1, 1, 3,3 )
        print(self.conv.weight.data)
        
        
    def forward(self, x):
        return super().forward(x)
    
    
class Model2(nn.Sequential):
    def __init__(self):
        super(Model2, self).__init__()
        self.add_module('padding', nn.ZeroPad2d(1))
        self.add_module('conv', nn.Conv2d(1, 1, kernel_size=3, padding=0, bias=False))
        self.conv.weight.data = torch.from_numpy(weights).view(1, 1, 3,3 )

        
    def forward(self, x):
        return super().forward(x)
    
    
if __name__ == '__main__':
    mod1 = Model1()
    mod2 = Model2()
    
    input_ = np.random.randint(low=1, high=99, size=(81, 81))
    input_ = torch.from_numpy(input_.astype(np.float)).view([1, 1, input_.shape[0], input_.shape[1]])

    res1 = mod1.forward(input_)
    res2 = mod2.forward(input_)
    assert np.allclose(res1.detach(), res2.detach())

It yields the same result.
Thus, as I’ve seen the Model2 approach within some Github projects (ex: https://github.com/Blade6570/Dilation-Pytorch-Semantic-Segmentation/blob/master/CAN_network.py), I am wondering if there is any advantage of using it.