Argh, so sorry, my bad! The line
last_h = h[0].view(self.n_layers, 2, batch_size, self.hidden_dim)

was supposed to be
last_h = h[0].view(self.n_layers, 2, batch_size, self.hidden_dim)[-1]

The [-1] gets the last of your 3 layers. Then the shape of l_last will be (2, batch_size, hidden_dim), with 2 reflecting the two directions. Then last_h[0] and last_h[1] will also makes sense with both having the shape (batch_size, hidden_dim), as will have final_h.