import torch.nn as nn import torch class RNN(nn.Module): def __init__(self, vocab_size, embedding_dim, hidden_dim, n_layers, bidirectional, dropout, pad_idx): """ @param vocab_size (int) @param embedding_dim (int) @param hidden_dim (int) @param n_layers (int) @param bidirectional (bool) @param dropout (float) @param pad_idx (int) """ super().__init__() self.embedding = nn.Embedding(vocab_size, embedding_dim, padding_idx = pad_idx) self.rnn = nn.LSTM(embedding_dim, hidden_dim, num_layers=n_layers, bidirectional=bidirectional, dropout=dropout) self.fc = nn.Linear(hidden_dim * 2, 1) self.dropout = nn.Dropout(dropout) def forward(self, text, text_lengths): """ @param text (torch.Tensor): shape = [sent len, batch size] @param text_lengths (torch.Tensor): shape = [batch size] @return """ #text = [sent len, batch size] embedded = self.dropout(self.embedding(text)) #embedded = [sent len, batch size, emb dim] #pack sequence # lengths need to be on CPU! packed_embedded = nn.utils.rnn.pack_padded_sequence(embedded, text_lengths.to('cpu')) packed_output, (hidden, cell) = self.rnn(packed_embedded) #unpack sequence output, output_lengths = nn.utils.rnn.pad_packed_sequence(packed_output) #output = [sent len, batch size, hid dim * num directions] #output over padding tokens are zero tensors #hidden = [num layers * num directions, batch size, hid dim] #cell = [num layers * num directions, batch size, hid dim] #concat the final forward (hidden[-2,:,:]) and backward (hidden[-1,:,:]) hidden layers #and apply dropout hidden = self.dropout(torch.cat((hidden[-2,:,:], hidden[-1,:,:]), dim = 1)) #hidden = [batch size, hid dim * num directions] return self.fc(hidden)