Lets take an example . If the input dimension was  (batch,seq_len, inputsize). Each batch goes through the below formular in parallel with other batches. Example. If we have an input of shape (2,2,2). From left, batch=2, seqlen=2, and inputsize=2.
tensor([[[0.6451, 0.8479],
         [0.3435, 0.2441]],

        [[0.0185, 0.4722],
         [0.8744, 0.2785]]])

[0.6451, 0.8479], = SEQ1   BATCH 1
         [0.3435, 0.2441] = SEQ2 BATCH 1

[0.0185, 0.4722],  SEQ1  BATCH 2
         [0.8744, 0.2785].   SEQ2  BATCH 2

TIME1:  SEQ1 BATCH1 Will go into the below formular AND at the same time SEQ1 BATCH2 will go in the below formular separately. So They will output two h<t>
TIME2: SEQ2 BATCH1 Will go into the below formular AND at the same time SEQ2 BATCH2 will go in the below formular BUT the h<t-1>  for SEQ2 BATCH1 will be the h<t> of  SEQ1 BATCH1. Similarly the h<t-1> for SEQ2 BATCH2 will be the h<t> of  SEQ1 BATCH2

Screen Shot 2021-03-16 at 10.51.49 PM1196×494 33.3 KB

I hope it helps. Similar to torch.lstm is torch.rnn. You can watch my youtube video on how it works with pen and paper
torch.rnn explained with Pen and Paper 1
For the difference between nn.LSTM  and    nn.LSTMCell : nn.LSTMCell is just a single implementation of the above formular while nn.LSTM is a layer that applies nn.LSTMCell in a for loop.
Reference Pytorch LSTM vs LSTMCell 1