In addition to the above code, I tried my own debugging by using only one batch. But found no luck in reproducing the bugs, but might be helpful to pinpoint where I miss. I use the following code to simulate the training & validation session with one batch from trainloader and testloader
The following are similar to my training code above, I just remove the epochs and batch loops in training and validation blocks. This works just fine without error from the LSTM expecting hidden_size exception:
epochs = 10
counter = 0
print_every = 10000
clip=5 # gradient clipping

net.train()
h = net.init_hidden(batch_size)

######## DEBUG #############
print("INIT_TRAIN_H :{}".format(len(h), h[0].shape))
############################

# batch loop
inputs, labels =  iter(train_loader).next()

train_on_gpu = torch.cuda.is_available()
if(train_on_gpu):
    inputs, labels = inputs.cuda(), labels.cuda()

# Creating new variables for the hidden state, otherwise
# we'd backprop through the entire training history
h = tuple([each.data for each in h])

# zero accumulated gradients
net.zero_grad()

# get the output from the model
output, h = net(inputs, h)

######## DEBUG #############
print("OUTPUT_TRAIN: {}, TRAIN_H: {}".format(output.shape, (len(h), h[0].shape)))
############################

# calculate the loss and perform backprop
loss = criterion(output.squeeze(), labels)
loss.backward()

# `clip_grad_norm` helps prevent the exploding gradient problem in RNNs / LSTMs.
nn.utils.clip_grad_norm_(net.parameters(), clip)
optimizer.step()


# Get validation loss
val_h = net.init_hidden(batch_size)


######## DEBUG #############
print("INIT_VAL_H :{}".format((len(val_h), val_h[0].shape)))
############################

val_losses = []
net.eval()

val_inputs, val_labels = iter(valid_loader).next()
# Creating new variables for the hidden state, otherwise
# we'd backprop through the entire training history
val_h = tuple([each.data for each in val_h])

if(train_on_gpu):
    val_inputs, val_labels = val_inputs.cuda(), val_labels.cuda()

output, val_h = net(inputs, val_h)

######## DEBUG #############
print("OUTPUT_VAL: {},  H_VAL: {}".format(output.shape, (len(val_h) ,val_h[0].shape)))
###########################

val_loss = criterion(output.squeeze(), val_labels)

val_losses.append(val_loss.item())

net.train()
# print("Epoch: {}/{}...".format(1, epochs),
#       "Step: {}...".format(counter),
#       "Loss: {:.6f}...".format(loss.item()),
#       "Val Loss: {:.6f}".format(np.mean(val_losses)))