我正在尝试在 Pytorch 中实现一个 seq2seq 模型,但我在批处理方面遇到了一些问题。 例如我有一批数据,其维度是
[batch_size, sequence_lengths, encoding_dimension]
批处理中每个示例的序列长度都不同。
现在,我设法通过将批处理中的每个元素填充到最长序列的长度来完成编码部分。
这样,如果我将一个形状与上述相同的批处理作为我的网络的输入,我将得到以下输出:
output, of shape
[batch_size, sequence_lengths, hidden_layer_dimension]
hidden state, of shape
[batch_size, hidden_layer_dimension]
cell state, of shape
[batch_size, hidden_layer_dimension]
现在,从输出,我为每个序列取最后一个相关元素,即沿 sequence_lengths
维度对应于最后一个非填充元素的元素顺序。因此,我得到的最终输出的形状是 [batch_size, hidden_layer_dimension]
。
但现在我遇到了从这个向量解码它的问题。如何处理同一批中不同长度序列的解码?我试着用谷歌搜索它并找到了 this ,但他们似乎没有解决问题。我想对整个批处理逐个元素地做,但是我有传递初始隐藏状态的问题,因为来自编码器的状态将是 [batch_size, hidden_layer_dimension]
的形状,而来自解码器的那些将具有 [1, hidden_layer_dimension]
的形状。
我错过了什么吗?感谢您的帮助!
最佳答案
你没有遗漏任何东西。我可以帮助你,因为我已经使用 PyTorch 开发了几个序列到序列的应用程序。我在下面给你一个简单的例子。
class Seq2Seq(nn.Module):
"""A Seq2seq network trained on predicting the next query."""
def __init__(self, dictionary, embedding_index, args):
super(Seq2Seq, self).__init__()
self.config = args
self.num_directions = 2 if self.config.bidirection else 1
self.embedding = EmbeddingLayer(len(dictionary), self.config)
self.embedding.init_embedding_weights(dictionary, embedding_index, self.config.emsize)
self.encoder = Encoder(self.config.emsize, self.config.nhid_enc, self.config.bidirection, self.config)
self.decoder = Decoder(self.config.emsize, self.config.nhid_enc * self.num_directions, len(dictionary),
self.config)
@staticmethod
def compute_decoding_loss(logits, target, seq_idx, length):
losses = -torch.gather(logits, dim=1, index=target.unsqueeze(1)).squeeze()
mask = helper.mask(length, seq_idx) # mask: batch x 1
losses = losses * mask.float()
num_non_zero_elem = torch.nonzero(mask.data).size()
if not num_non_zero_elem:
return losses.sum(), 0 if not num_non_zero_elem else losses.sum(), num_non_zero_elem[0]
def forward(self, q1_var, q1_len, q2_var, q2_len):
# encode the query
embedded_q1 = self.embedding(q1_var)
encoded_q1, hidden = self.encoder(embedded_q1, q1_len)
if self.config.bidirection:
if self.config.model == 'LSTM':
h_t, c_t = hidden[0][-2:], hidden[1][-2:]
decoder_hidden = torch.cat((h_t[0].unsqueeze(0), h_t[1].unsqueeze(0)), 2), torch.cat(
(c_t[0].unsqueeze(0), c_t[1].unsqueeze(0)), 2)
else:
h_t = hidden[0][-2:]
decoder_hidden = torch.cat((h_t[0].unsqueeze(0), h_t[1].unsqueeze(0)), 2)
else:
if self.config.model == 'LSTM':
decoder_hidden = hidden[0][-1], hidden[1][-1]
else:
decoder_hidden = hidden[-1]
decoding_loss, total_local_decoding_loss_element = 0, 0
for idx in range(q2_var.size(1) - 1):
input_variable = q2_var[:, idx]
embedded_decoder_input = self.embedding(input_variable).unsqueeze(1)
decoder_output, decoder_hidden = self.decoder(embedded_decoder_input, decoder_hidden)
local_loss, num_local_loss = self.compute_decoding_loss(decoder_output, q2_var[:, idx + 1], idx, q2_len)
decoding_loss += local_loss
total_local_decoding_loss_element += num_local_loss
if total_local_decoding_loss_element > 0:
decoding_loss = decoding_loss / total_local_decoding_loss_element
return decoding_loss
完整源码可以看here .此应用程序是关于在给定当前网络搜索查询的情况下预测用户的下一个网络搜索查询。
您问题的回答者:
How do I handle a decoding of sequences of different lengths in the same batch?
你有填充序列,所以你可以认为所有序列的长度都相同。但是当您计算损失时,您需要使用掩码忽略那些填充项的损失。
我用过 masking在上面的示例中实现相同的技术。
此外,您完全正确:您需要逐个元素解码小批量。初始解码器状态 [batch_size, hidden_layer_dimension]
也很好。您只需在维度 0 处取消压缩,使其成为 [1, batch_size, hidden_layer_dimension]
。
请注意,您不需要遍历批处理中的每个示例,您可以一次执行整个批处理,但您需要遍历序列的元素。
关于python - 批处理如何在 pytorch 的 seq2seq 模型中工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49283435/