PyTorch RNN classes have a bidirectional
keyword flag. So this is quite easy. You should simply change to
class LSTMTagger(nn.Module):
def __init__(self, embedding_dim, hidden_dim, vocab_size, tagset_size):
super(LSTMTagger, self).__init__()
self.hidden_dim = hidden_dim
self.word_embeddings = nn.Embedding(vocab_size, embedding_dim)
# The LSTM takes word embeddings as inputs, and outputs hidden states
# with dimensionality hidden_dim.
self.lstm = nn.LSTM(embedding_dim, hidden_dim, bidirectional=True) # <- change here
# The linear layer that maps from hidden state space to tag space
self.hidden2tag = nn.Linear(hidden_dim * 2, tagset_size)
self.hidden = self.init_hidden()
def init_hidden(self):
# Before we've done anything, we dont have any hidden state.
# Refer to the Pytorch documentation to see exactly
# why they have this dimensionality.
# The axes semantics are (num_layers * num_directions, minibatch_size, hidden_dim)
return (autograd.Variable(torch.zeros(2, 1, self.hidden_dim)),
autograd.Variable(torch.zeros(2, 1, self.hidden_dim))) # <- change here: first dim of hidden needs to be doubled
def forward(self, sentence):
embeds = self.word_embeddings(sentence)
lstm_out, self.hidden = self.lstm(
embeds.view(len(sentence), 1, -1), self.hidden)
tag_space = self.hidden2tag(lstm_out.view(len(sentence), -1))
tag_scores = F.log_softmax(tag_space, dim=1)
return tag_scores
The two lines I changed are marked by # <- change here
edit: changed another line I missed. see below for details.