The issue was resolved once I used Tensor View 2 to reshape the mini-batches for the features in the training and in the validation set. As a side note, view() enable fast and memory-efficient reshaping, slicing, and element-wise operations, by avoiding an explicit data copy.
It turned out that in the earlier implementation torch.unsqueeze() did not reshape the batches into tensors with the dimensions (batch size, timesteps, number of features). Instead, the function unsqueeze(dim=0) returns a new tensor with a singleton dimension inserted at the Oth index.
So, the mini batches for the feature sets is shaped as follows x_batch = x_batch.view([batch_size, -1, n_features]).to(device)
Then, the new training loop becomes:
for epoch in range(n_epochs):
    batch_losses = []
    for x_batch, y_batch in train_loader:
        x_batch = x_batch.view([batch_size, -1, n_features]).to(device) # <---
        y_batch = y_batch.to(device)
        loss = train_step(x_batch, y_batch)
        batch_losses.append(loss)
    training_loss = np.mean(batch_losses)
    train_losses.append(training_loss)    
    with torch.no_grad():
        batch_val_losses = []
        for x_val, y_val in val_loader:
            x_val = x_val.view([batch_size, -1, n_features]).to(device) # <---
            y_val = y_val.to(device)        
            model.eval()
            yhat = model(x_val)
            val_loss = criterion(y_val, yhat).item()
            batch_val_losses.append(val_loss)
        validation_loss = np.mean(batch_val_losses)
        val_losses.append(validation_loss)
    
    print(f"[{epoch+1}] Training loss: {training_loss:.4f}\t Validation loss: {validation_loss:.4f}")

Here’s the output:
[1] Training loss: 0.0235	 Validation loss: 0.0173
[2] Training loss: 0.0149	 Validation loss: 0.0086
[3] Training loss: 0.0083	 Validation loss: 0.0074
[4] Training loss: 0.0079	 Validation loss: 0.0069
[5] Training loss: 0.0076	 Validation loss: 0.0069

                          ...

[96] Training loss: 0.0025	 Validation loss: 0.0028
[97] Training loss: 0.0024	 Validation loss: 0.0027
[98] Training loss: 0.0027	 Validation loss: 0.0033
[99] Training loss: 0.0027	 Validation loss: 0.0030
[100] Training loss: 0.0023	 Validation loss: 0.0028