Hi albanD,
Indeed, very strange! Your example works as expected. But what happens if you replace xb with the training data? That is, construct x_train as in the tutorial (self-contained cell below). In my case this returns null gradients; can you reproduce this?
import torch
import pickle
import gzip
import math

PATH_TO_MNIST = '/full/path/to/MNIST/data/'    # replace with path on local machine!
FILENAME = 'mnist.pkl.gz'

# open gzip file in mode for reading binary (`rb`) data:
with gzip.open(PATH_TO_MNIST + FILENAME, 'rb') as file:
    ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(file, encoding="latin-1")
    
# convert from numpy array to PyTorch tensor:
x_train, y_train, x_valid, y_valid = map(torch.from_numpy, (x_train, y_train, x_valid, y_valid))

# initialize weights:
weights = torch.randn(784,10)/math.sqrt(784)
weights.requires_grad_()

xb = x_train[:64]    # mini-batch of size 64

prod = xb @ weights

iden = torch.ones([prod.shape[0],prod.shape[1]]) 
prod.backward(iden)
print(weights.grad)