If you’re interested in the last hidden state, i.e., the hidden state after the last time step, I wouldn’t bother with gru_out and simply use hidden (w.r.t. to your examples). According to the docs:

hidden.shape = (num_layers*num_directions, batch, hidden_size)
layers can be separated using  h_n.view(num_layers, num_directions, batch, hidden_size)


So you shouldn’t simply do hidden[-1] but first do a view() to separate the num_layers and num_directions (1 or 2). If you do
hidden = hidden.view(num_layers, 2, batch, hidden_size) # 2 for bidirectional
last_hidden = hidden[-1]

then last_hidden.shape = (2, batch, hidden_size) and you can do
last_hidden_fwd = last_hidden[0]
last_hidden_bwd = last_hidden[1]

If you want to sum them up or concatenate them is up to you. You can also have a look at this related post 126.