In forward(), using null value made the error message disappear.
self.rnn(X, None)

Now, the training loss decreases nicely but suddenly becomes a huge positive value. Following other examples, I can see that this is not the ideal way. Any suggestion to handle hidden value and initial weight is much appreciated.