If you’re going to pass an encoder_hidden to your decoder you don’t even need the initHidden method. Your gru will automatically set the initial hidden state to zero, process the whole sequence and pop out an output and hidden_state.
There are a few ways you can pass these to a decoder. The easiest is to merge the forward and backward features with addition rather than concatenation, that way the dimensions stay the same.
 encoder_out = (encoder_out[:, :, :self.hidden_dim] +
                encoder_out[:, :, self.hidden_dim:])

You should also be able to pass the encoder hidden state to the decoder by passing the last layers encoder state to the first layer of the decoder. Optionally, if your encoder has the same or more layers than the decoder you could take the last n layers with n being the number of layers in the decoder.
decoder_hidden = encoder_hidden[-decoder.n_layers:] # take what we need from encoder
I’ll shamelessly link you to my own code for details:

  
      github.com
  
  
    A-Jacobson/minimal-nmt/blob/master/nmt_tutorial.ipynb 148
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "import torch\n",
    "import random\n",
    "from torch import nn\n",
    "from torch.autograd import Variable\n",
    "from torch.optim import Adam\n",
    "import torch.nn.functional as F\n",
    "import torchtext\n",
    "from torchtext.datasets import Multi30k\n",
    "from torchtext.data import Field, BucketIterator\n",
    "from torch.nn.utils import clip_grad_norm\n",
    "import spacy"


  This file has been truncated. show original