pytorch教程通过定义输入和隐藏层,并手动将隐藏层反馈到网络中以记住状态,从而很好地说明了一个简单的RNN。这种灵活性使您可以非常轻松地执行教师强制。
问题1 :在使用原生nn.RNN()
模块时如何执行教师强制(因为整个序列一次被送入)?示例简单的RNN网络将是:
class SimpleRNN(nn.Module):
def __init__(self, vocab_size,
embedding_dim,
batch_sz,
hidden_size=128,
nlayers=1,
num_directions=1,
dropout=0.1):
super(SimpleRNN, self).__init__()
self.batch_sz = batch_sz
self.hidden_size = hidden_size
self.encoder = nn.Embedding(vocab_size, embedding_dim)
self.rnn = nn.RNN(embedding_dim, hidden_size, nlayers, dropout=0.5)
self.decoder = nn.Linear(hidden_size, vocab_size)
def init_hidden(self):
return autograd.Variable(torch.zeros(nlayers, batch_sz, hidden_size)).cuda()
def forward(self, inputs, hidden):
# -- encoder returns:
# -- [batch_sz, seq_len, embed_dim]
encoded = self.encoder(inputs)
_, seq_len, _ = encoded.size()
# -- rnn returns:
# -- output.size() = [seq_len, batch_sz, hidden_sz]
# -- hidden.size() = [nlayers, batch_sz, hidden_sz]
output, hidden = self.rnn(encoded.view(seq_len, batch_sz, embedding_dim), hidden)
# -- decoder returns:
# -- output.size() = [batch_sz, seq_len, vocab_size]
output = F.log_softmax(decoder(output.view(batch_sz, seq_len, self.hidden_size)))
return output, hidden
我可以通过以下方式呼叫网络:
model = SimpleRNN(vocab_size, embedding_dim, batch_sz).cuda()
x_data, y_data = get_sequence_data(train_batches[0])
output, hidden = model(x_data, model.init_hidden())
为了完整起见,我的形状为x_data
,output
和hidden
:
print(x_data.size(), output.size(), hidden.size())
torch.Size([32, 80]) torch.Size([32, 80, 4773]) torch.Size([1, 32, 128])
问题2 :是否可以使用此SimpleRNN
网络然后逐字逐句生成序列,首先将其<GO_TOKEN>
输入并迭代直到已达到<END_TOKEN>
?我问,因为当我这样做时:
x_data = autograd.Variable(torch.LongTensor([[word2idx['<GO>']]]), volatile=True).cuda()
output, hidden = model(x_data, model.init_hidden(1))
print(output, output.sum())
我得到所有0的output
和output.sum() = 0
。即使在训练网络并反向传播损失后,我也能得到这个。有什么想法吗?
问题3 :如果不是非常低效,是否可以逐字训练SimpleRNN
网络,类似于所示的pytorch教程(此处)[{{3 (虽然他们在那里逐个训练)。
答案 0 :(得分:2)
问题1。
在这种情况下隐式执行教师强制,因为你的x_data是[seq_len,batch_size],它将在seq_len中的每个项目中作为输入提供,而不是使用实际输出进行下一次输入。
问题2。
你的model.init_hidden不接受任何输入,但看起来你正试图添加批量大小,也许你可以检查一下,其他一切似乎都没问题。虽然您需要在输出上执行max()或multinomial(),然后才能反馈它。
问题3。
是的,你可以这样做,是的,效率非常低。这是CUDNN LSTM内核的限制