The docs say: h_n of shape (num_layers * num_directions, batch, hidden_size); the layers can be separated using h_n.view(num_layers, num_directions, batch, hidden_size). So in the bidirectional case, you have 2 tensors with hidden_size for each direction. I think most people just concatenate them before the next step, e.g., pushing through a Linear(2*hidden_size, output_size). I think I also saw both tensors being averaged or summed up element-wise.
Regarding your bonus question: I think your right. At least I got essentially the same result when I compared using PackedSequence with variable sequence lengths and padding vs. sequences with the same length and no padding.