【问题标题】:Bidirectional LSTM output question in PyTorchPyTorch 中的双向 LSTM 输出问题
【发布时间】:2019-03-31 07:36:19
【问题描述】:

您好,我有一个关于如何从 BI-LSTM 模块的输出中收集正确结果的问题。

假设我有一个长度为 10 的序列输入到具有 100 个隐藏单元的单层 LSTM 模块中:

lstm = nn.LSTM(5, 100, 1, bidirectional=True)

output 的形状:

[10 (seq_length), 1 (batch),  200 (num_directions * hidden_size)]
# or according to the doc, can be viewed as
[10 (seq_length), 1 (batch),  2 (num_directions), 100 (hidden_size)]

如果我想在两个方向(两个 100 维向量)获得第三个(1-index)输入的输出,我该如何正确地做到这一点?

我知道output[2, 0] 会给我一个 200 维向量。 这 200 个暗淡向量是否代表两个方向的第三个输入的输出?

困扰我的是,在进行反向馈送时,第三个(1-index)输出向量是从第 8 个(1-index)输入计算出来的,对吧?

pytorch 会自动处理这个问题并根据方向对输出进行分组吗?

谢谢!

【问题讨论】:

    标签: machine-learning neural-network deep-learning lstm pytorch


    【解决方案1】:

    是的,当使用 BiLSTM 时,方向的隐藏状态只是连接起来(中间之后的第二部分是反向序列馈送的隐藏状态)。
    所以在中间分开就可以了。

    随着从右到左维度的重塑工作,您在分离两个方向时不会有任何问题。


    这是一个小例子:

    # so these are your original hidden states for each direction
    # in this case hidden size is 5, but this works for any size
    direction_one_out = torch.tensor(range(5))
    direction_two_out = torch.tensor(list(reversed(range(5))))
    print('Direction one:')
    print(direction_one_out)
    print('Direction two:')
    print(direction_two_out)
    
    # before outputting they will be concatinated 
    # I'm adding here batch dimension and sequence length, in this case seq length is 1
    hidden = torch.cat((direction_one_out, direction_two_out), dim=0).view(1, 1, -1)
    print('\nYour hidden output:')
    print(hidden, hidden.shape)
    
    # trivial case, reshaping for one hidden state
    hidden_reshaped = hidden.view(1, 1, 2, -1)
    print('\nReshaped:')
    print(hidden_reshaped, hidden_reshaped.shape)
    
    # This works as well for abitrary sequence lengths as you can see here
    # I've set sequence length here to 5, but this will work for any other value as well
    print('\nThis also works for more multiple hidden states in a tensor:')
    multi_hidden = hidden.expand(5, 1, 10)
    print(multi_hidden, multi_hidden.shape)
    print('Directions can be split up just like this:')
    multi_hidden = multi_hidden.view(5, 1, 2, 5)
    print(multi_hidden, multi_hidden.shape)
    

    输出:

    Direction one:
    tensor([0, 1, 2, 3, 4])
    Direction two:
    tensor([4, 3, 2, 1, 0])
    
    Your hidden output:
    tensor([[[0, 1, 2, 3, 4, 4, 3, 2, 1, 0]]]) torch.Size([1, 1, 10])
    
    Reshaped:
    tensor([[[[0, 1, 2, 3, 4],
              [4, 3, 2, 1, 0]]]]) torch.Size([1, 1, 2, 5])
    
    This also works for more multiple hidden states in a tensor:
    tensor([[[0, 1, 2, 3, 4, 4, 3, 2, 1, 0]],
    
            [[0, 1, 2, 3, 4, 4, 3, 2, 1, 0]],
    
            [[0, 1, 2, 3, 4, 4, 3, 2, 1, 0]],
    
            [[0, 1, 2, 3, 4, 4, 3, 2, 1, 0]],
    
            [[0, 1, 2, 3, 4, 4, 3, 2, 1, 0]]]) torch.Size([5, 1, 10])
    Directions can be split up just like this:
    tensor([[[[0, 1, 2, 3, 4],
              [4, 3, 2, 1, 0]]],
    
    
            [[[0, 1, 2, 3, 4],
              [4, 3, 2, 1, 0]]],
    
    
            [[[0, 1, 2, 3, 4],
              [4, 3, 2, 1, 0]]],
    
    
            [[[0, 1, 2, 3, 4],
              [4, 3, 2, 1, 0]]],
    
    
            [[[0, 1, 2, 3, 4],
              [4, 3, 2, 1, 0]]]]) torch.Size([5, 1, 2, 5])
    

    希望这会有所帮助! :)

    【讨论】:

    【解决方案2】:

    我知道 output[2, 0] 会给我一个 200 维向量。这 200 个暗淡向量是否代表两个方向的第三个输入的输出?

    答案是

    LSTM模块输出的output张量是前向LSTM输出和后向LSTM输出在输入序列中对应位置的串联。 而h_n tensor 是最后一个时间戳的输出,它是前向 LSTM 中 lsat 标记的输出,但在后向 LSTM 中是第一个标记。

    In [1]: import torch
       ...: lstm = torch.nn.LSTM(input_size=5, hidden_size=3, bidirectional=True)
       ...: seq_len, batch, input_size, num_directions = 3, 1, 5, 2
       ...: in_data = torch.randint(10, (seq_len, batch, input_size)).float()
       ...: output, (h_n, c_n) = lstm(in_data)
       ...: 
    
    In [2]: # output of shape (seq_len, batch, num_directions * hidden_size)
       ...: 
       ...: print(output)
       ...: 
    tensor([[[ 0.0379,  0.0169,  0.2539,  0.2547,  0.0456, -0.1274]],
    
            [[ 0.7753,  0.0862, -0.0001,  0.3897,  0.0688, -0.0002]],
    
            [[ 0.7120,  0.2965, -0.3405,  0.0946,  0.0360, -0.0519]]],
           grad_fn=<CatBackward>)
    
    In [3]: # h_n of shape (num_layers * num_directions, batch, hidden_size)
       ...: 
       ...: print(h_n)
       ...: 
    tensor([[[ 0.7120,  0.2965, -0.3405]],
    
            [[ 0.2547,  0.0456, -0.1274]]], grad_fn=<ViewBackward>)
    
    In [4]: output = output.view(seq_len, batch, num_directions, lstm.hidden_size)
       ...: print(output[-1, 0, 0])  # forward LSTM output of last token
       ...: print(output[0, 0, 1])  # backward LSTM output of first token
       ...: 
    tensor([ 0.7120,  0.2965, -0.3405], grad_fn=<SelectBackward>)
    tensor([ 0.2547,  0.0456, -0.1274], grad_fn=<SelectBackward>)
    
    In [5]: h_n = h_n.view(lstm.num_layers, num_directions, batch, lstm.hidden_size)
       ...: print(h_n[0, 0, 0])  # h_n of forward LSTM
       ...: print(h_n[0, 1, 0])  # h_n of backward LSTM
       ...: 
    tensor([ 0.7120,  0.2965, -0.3405], grad_fn=<SelectBackward>)
    tensor([ 0.2547,  0.0456, -0.1274], grad_fn=<SelectBackward>)
    

    【讨论】:

    • 嘿 dd.,我已经试图找出你的答案已经一个星期了,但我仍然不能,有点帮助?您的回答向我表明 output[-1, 0, :] 没有提供所需的输出,但应该像您一样采用中间点(命令 4)。你能详细说明一下吗?确认还是什么?我的问题真的是,如何获得 h_n,RNN 的最后输出?
    • 特别是这似乎与您说是的 OP 问题相矛盾? towardsdatascience.com/…
    猜你喜欢
    • 2019-05-08
    • 2021-08-19
    • 2019-07-11
    • 2020-08-31
    • 2019-11-12
    • 2019-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多