Also - apologies if this is beating it to the ground, but can you explain the reasoning behind this:
.view(batch_sz * seq_len, -1).view(batch_sz, seq_len, self.vocab_size)
The output from the decoder is already in dimensions [batch_sz_seq_len, vocab_size] – what’s the point of resizing to [batch_sz*seq_len, -1] and then resizing again back to the original dimensions?  Unless I’m misunderstanding something and you meant to actually write:
output = F.log_softmax(dec_out.view(batch_size * seq_len, -1)).view(batch_sz, seq_len, self.hidden_size)