理论:
回想一下,LSTM 为序列中的每个输入输出一个向量。您正在使用句子,它们是一系列单词(可能转换为索引,然后嵌入为向量)。来自 LSTM PyTorch tutorial 的这段代码清楚地表明了我的意思(***强调我的意思):
lstm = nn.LSTM(3, 3) # Input dim is 3, output dim is 3
inputs = [autograd.Variable(torch.randn((1, 3)))
for _ in range(5)] # make a sequence of length 5
# initialize the hidden state.
hidden = (autograd.Variable(torch.randn(1, 1, 3)),
autograd.Variable(torch.randn((1, 1, 3))))
for i in inputs:
# Step through the sequence one element at a time.
# after each step, hidden contains the hidden state.
out, hidden = lstm(i.view(1, 1, -1), hidden)
# alternatively, we can do the entire sequence all at once.
# the first value returned by LSTM is all of the hidden states throughout
# the sequence. the second is just the most recent hidden state
# *** (compare the last slice of "out" with "hidden" below, they are the same)
# The reason for this is that:
# "out" will give you access to all hidden states in the sequence
# "hidden" will allow you to continue the sequence and backpropagate,
# by passing it as an argument to the lstm at a later time
# Add the extra 2nd dimension
inputs = torch.cat(inputs).view(len(inputs), 1, -1)
hidden = (autograd.Variable(torch.randn(1, 1, 3)), autograd.Variable(
torch.randn((1, 1, 3)))) # clean out hidden state
out, hidden = lstm(inputs, hidden)
print(out)
print(hidden)
再来一次:比较最后一段“out”和下面的“hidden”,它们是一样的。 为什么?嗯……
如果您熟悉 LSTM,我现在推荐 PyTorch LSTM docs。在输出部分下,通知 h_t 在每个 t 处输出。
现在,如果您不习惯 LSTM 样式的方程,请查看 Chris Olah 的 LSTM blog post。向下滚动到展开的网络图:
当您逐字输入句子时 (x_i-by-x_i+1),您会从每个时间步得到一个输出。您想解释整个句子以对其进行分类。所以你必须等到 LSTM 看到所有的单词。也就是说,您需要取h_t,其中t 是您句子中的单词数。
代码:
这是一个编码reference。我不会复制粘贴整个内容,只复制相关部分。奇迹发生在self.hidden2label(lstm_out[-1])
class LSTMClassifier(nn.Module):
def __init__(self, embedding_dim, hidden_dim, vocab_size, label_size, batch_size):
...
self.word_embeddings = nn.Embedding(vocab_size, embedding_dim)
self.lstm = nn.LSTM(embedding_dim, hidden_dim)
self.hidden2label = nn.Linear(hidden_dim, label_size)
self.hidden = self.init_hidden()
def init_hidden(self):
return (autograd.Variable(torch.zeros(1, self.batch_size, self.hidden_dim)),
autograd.Variable(torch.zeros(1, self.batch_size, self.hidden_dim)))
def forward(self, sentence):
embeds = self.word_embeddings(sentence)
x = embeds.view(len(sentence), self.batch_size , -1)
lstm_out, self.hidden = self.lstm(x, self.hidden)
y = self.hidden2label(lstm_out[-1])
log_probs = F.log_softmax(y)
return log_probs