Thank you again, but this is what exactly I have done. Actually I’m comparing the following two pieces of code:
for epoch in range(n_epochs):
        for _, da in enumerate(trainloader, 0):
            inputs  = torch.tensor(da[:,:-2].numpy())
            targets = da[:,-2:]
            optimizer.zero_grad()
            inputs  = torch.tensor(np.array([[pp for pp in p] for p in inputs]).astype(np.float32))
            outputs = model(inputs.to(device))
            loss = model.loss_f(outputs, targets.to(device)) 
            
            loss.backward()
            optimizer.step()

And:
for epoch in range(n_epochs):
      model.train()
      optimizer.zero_grad()
      outputs    = model(X.to(device))
      loss       = model.loss_f(outputs, Y.to(device))
      
      loss.backward()
      optimizer.step()

where:
device = 'cuda' if torch.cuda.is_available() else 'cpu'

The second one seems to be faster. However, the second seems to be less efficient than the first one in some cases. I need to improve the first one.