The following chunk of code might complement the answer of @ptrblck .
import torch
from torch import nn
import numpy as np
np.random.seed(1)

def convolve_slice(X,W,b,stride=2):
    xH,xW=X.shape
    wH,wW=W.shape
    vH,vW= (xH-wH)//stride +1,(xW-wW)//stride +1    
    assert vH==vW
    assert wH==wW
    k=wH
    v=np.zeros((vH,vW)) # output shape
    for i in range(vH):
        for j in range(vH):
            v[i,j]=np.sum(X[stride*i:(stride*i)+k,stride*j:(stride*j)+k] *W) +b    
    return v


xH,xW=7,7
stride=2
x=np.random.randn(xH,xW)

# show it if you will.
#plt.imshow(x, interpolation='none')
#plt.show()


k = 3 # kernel/filter shape.
conv = nn.Conv1d(in_channels=1,
                 kernel_size=(k, k),
                 out_channels=1, stride=stride)
# from numpy to torch
x_torch = torch.from_numpy(x)
x_torch = x_torch.float()
x_torch = x_torch.view(1, 1, xH, xW)
print(conv(x_torch))

w0 = conv.weight.data.numpy()
b0 = conv.bias.data.numpy()
w0 = w0.reshape(k, k)

m=convolve_slice(x,w0,b0,2)
print(m)