I’ll give the “functional” version a try.  your first suggestion (loss_function(output,y_data)) does not work because I guess it expects either 2 or 4 dimensions.
One approach to doing it all in one line is actually like so:
(torch.gather(-output[:,:-1,:],2,y_data[:,1:].unsqueeze(2)).squeeze().data * mask.cuda()).sum()

Where mask corresponds to a [batch_sz, max_seq_len-1] tensor of 1s and 0s corresponding to word or <PAD>, respectively.  That’s a pretty ugly solution in my opinion, and I haven’t even tried to check whether it’s faster or slower.  Plus, it requires the creation of a new mask tensor that needs to be copied to the GPU for each batch evaluation.
I’ll give your “functional” solution a try and hopefully that solves it.