Python 从Pytork中的BiLSTM(BiGRU)获取最后一个状态

Python 从Pytork中的BiLSTM(BiGRU)获取最后一个状态,python,lstm,pytorch,Python,Lstm,Pytorch,在阅读了几篇文章之后,我仍然对从BiLSTM获取最后隐藏状态的实现的正确性感到困惑 来自最后一个来源(4)的方法对我来说似乎是最干净的,但我仍然不确定是否正确理解了线程。我是否使用了LSTM和反向LSTM的正确最终隐藏状态?这是我的实现 正确吗?在一般情况下,如果您想创建自己的BiLSTM网络,您需要创建两个常规LSTM,其中一个使用常规输入序列,另一个使用反向输入序列。完成两个序列的馈送后,只需从两个网络中获取最后的状态,并以某种方式将它们连接在一起(求和或连接) 据我所知,您正在使

在阅读了几篇文章之后,我仍然对从BiLSTM获取最后隐藏状态的实现的正确性感到困惑

  • 来自最后一个来源(4)的方法对我来说似乎是最干净的,但我仍然不确定是否正确理解了线程。我是否使用了LSTM和反向LSTM的正确最终隐藏状态?这是我的实现


    正确吗?

    在一般情况下,如果您想创建自己的BiLSTM网络,您需要创建两个常规LSTM,其中一个使用常规输入序列,另一个使用反向输入序列。完成两个序列的馈送后,只需从两个网络中获取最后的状态,并以某种方式将它们连接在一起(求和或连接)

    据我所知,您正在使用内置的BiLSTM,如中所示(在nn.LSTM构造函数中设置
    bidirectional=True
    )。然后,在为批处理添加数据之后,您将获得连接的输出,因为PyTorch将为您处理所有的麻烦

    如果是这样的话,你想求隐藏状态的和,那么你必须

    u_emb_batch = (lasthidden[0, :, :] + lasthidden[1, :, :])
    
    假设只有一层。如果你有更多的图层,你的变体看起来会更好

    这是因为结果是结构化的(请参见):

    h\u n形状(num\u layers*num\u directions,batch,hidden\u size):包含t=seq\u len的隐藏状态的张量

    顺便说一下

    u_emb_batch_2 = output[-1, :, :HIDDEN_DIM] + output[-1, :, HIDDEN_DIM:]
    

    应提供相同的结果。

    以下是对使用未打包序列的人员的详细说明:

    输出的形状为
    (顺序、批次、数量方向*隐藏大小)
    (请参阅)。这意味着您的GRU的向前和向后过程的输出沿第三维连接

    在您的示例中,假设
    batch=2
    hidden_size=256
    ,您可以通过执行以下操作轻松分离向前和向后过程的输出:

    output=output.view(-1,2,2,256)#(seq_len,batch_size,num_directions,hidden_size)
    output_forward=输出[:,:,0,:]#(顺序、批次大小、隐藏大小)
    output_backward=输出[:,:,1,:]#(顺序、批次大小、隐藏大小)
    
    (注意:
    -1
    告诉pytorch从其他维度推断该维度。参见问题。)

    同样地,您可以在shape
    的原始
    输出上使用该函数(seq\u len,batch,num\u directions*hidden\u size)

    现在,您可以使用
    seqlength
    (对其进行整形后)来确定向前传球的最后一个隐藏状态,并通过选择位置
    0
    处的元素来确定向后传球的最后一个隐藏状态

    # First we unsqueeze seqlengths two times so it has the same number of
    # of dimensions as output_forward
    # (batch_size) -> (1, batch_size, 1)
    lengths = seqlengths.unsqueeze(0).unsqueeze(2)
    
    # Then we expand it accordingly
    # (1, batch_size, 1) -> (1, batch_size, hidden_size) 
    lengths = lengths.expand((1, -1, output_forward.size(2)))
    
    last_forward = torch.gather(output_forward, 0, lengths - 1).squeeze(0)
    last_backward = output_backward[0, :, :]
    
    注意,由于基于0的索引,我从
    长度中减去了
    1


    A该点的
    last\u forward
    last\u backward
    均为
    (批量大小,隐藏尺寸)
    我测试了biLSTM输出和h\u n:

    #x的形状是大小(批量大小、时间步长、输入大小)
    #输出形状(批次大小、时间步长、隐藏大小*数量方向)
    #h\u n的形状是大小(数量方向、批次大小、隐藏大小)
    输出(h_n,_c_n)=biLSTM(x)
    打印('从反转输出的第0步==h_n从反转?',
    输出[:,0,隐藏大小:]==h\u n[1])
    print('反向输出的步骤-1==反向输出的h_n?',
    输出[:,-1,隐藏大小:]==h\U n[1])
    
    输出

    step 0 of output from reverse == h_n from reverse? True
    step -1 of output from reverse == h_n from reverse? False
    
    h_n[0,:,:] + h_n[1,:,:]
    
    这证实了反向的h_n是第一时间步的隐藏状态

    因此,如果您确实需要上一个时间步的隐藏状态(从正向和反向),则应使用:

    sum_lasthidden = output[:, -1, :hidden_size] + output[:, -1, hidden_size:]
    
    不是

    step 0 of output from reverse == h_n from reverse? True
    step -1 of output from reverse == h_n from reverse? False
    
    h_n[0,:,:] + h_n[1,:,:]
    
    As
    h_n[1,:,:]
    是从相反方向开始的第一个时间步的隐藏状态

    那么@igrinis的答案是什么

    u_emb_batch = (lasthidden[0, :, :] + lasthidden[1, :, :])
    
    这是不对的


    但从理论上讲,反向的最后一个时间步隐藏状态只包含序列最后一个时间步的信息。

    您的假设是正确的,我正在使用内置的BiLSTM(分别为BiGRUs)来避免麻烦,我正在试验多层架构。谢谢你的回复@toBTW:是的,但如果我要使用“输出”,我首先需要将它从打包序列解包到填充序列,这也是我想要避免的。我还有一大堆问题:@1:为什么我的变体不适合1层@2:在我错过的文档(或其他官方来源)中,是否有任何地方说明了在lasthidden变量中BiRNN的情况下对隐藏状态的排序?1。这很好,但我很惊讶地看到不寻常的数字2。对于所有层,首先(索引0)为正常RNN,然后反向。看看nn.rnnbase的来源我想你在上面犯了个错误。不应该是:
    output=output.view(-1,2,2256)#(seq_len,batch_size,num_directions,hidden_size)
    ?然后就是:
    output_forward=output[:,:,0,:]#(seq_len,batch_size,direction)output_backward=output[:,:,:,1,:]#(seq_len,batch_size,direction)
    pytorch在v0.4.0中时我写了这个答案,如果你看看当时的文档(),输出维度是
    seq_len,batch,隐藏的大小*数量方向
    ,但在当前版本中,它们是
    顺序、批次、数量方向*隐藏的大小
    。考虑到新的订单,我更新了答案。谢谢