pp18:

what is the size of first hidden layer and second layer output. Are they both 20?


Yes.



 pp18:

is there way to assign different hidden sizes for different lstm layer?


No.



 pp18:

input_seq = Variable(torch.randn(time_steps, batch_size, in_size)) 
# size: [torch.FloatTensor of size 10x3x5] i.e there are 10 sequences each of 
# length 3 with 5 features.



Wrong.  there are 3 sequences each of length 10 with 5 features.
That should clear up the doubts concerning output_seq and last_output



 pp18:

target = Variable(torch.LongTensor(batch_size).random_(0, classes_no-1)) 
# [torch.LongTensor of size 3]  # containing numbers from 0 to classes_no-1
# if you only have three classes, the target tensor would need to contain only integers from 0 to 3.



Concerning the loss
loss = nn.CrossEntropyLoss() # defines which loss function to use.
err = loss(last_output, target) # calculates that loss.

Remarks…
You may need more hidden units in the LSTM layers. In which case you would need to add a Linear layer to squeeze the last_output down to the right size for the number of classes.