PyTorch中的双向LSTM输出问题

yrefmtwq  于 2023-08-05  发布在  其他
关注(0)|答案(3)|浏览(116)

嗨,我有一个关于如何从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索引)输入的输出,我如何正确地做到这一点?
我知道output[2, 0]会给予我一个200-dim矢量。这个200暗矢量是否表示两个方向上的第三输入的输出?
一件困扰我的事情是,当做反向馈送时,第三个(1-index)输出向量是从第八个(1-index)输入计算出来的,对吗?
pytorch会自动处理这个问题,并根据方向对输出进行分组吗?
谢谢你,谢谢

ctzwtxfj

ctzwtxfj1#

是的,当使用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])

  • 希望这有帮助!:)*
fzwojiic

fzwojiic2#

我知道output[2,0]会给予我一个200-dim的向量。这个200个暗矢量是否表示两个方向上的第三个输入的输出?
答案是
LSTM模块输出的outputTensor是输入序列中相应位置处的前向LSTM输出和后向LSTM输出的级联。h_nTensor是最后一个时间戳的输出,它是前向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>)

字符串

blmhpbnm

blmhpbnm3#

我知道output[2,0]会给予我一个200-dim的向量。这个200个暗矢量是否表示两个方向上的第三个输入的输出?
是的,也不是。它确实表示两个方向上索引2处的输入的输出,但不是每个方向上的第3个输入。RNN看到的正向方向上的第三个输入在索引2处,并且反向方向上的第三个输入在索引7处。
此外,就每个方向上的最后可能输出而言,以下解释是重要的。在正向方向上,最后一个输出将在索引9(第10个输出),而在反向方向上的最后一个输出将在索引0(第10个输出)。
如果您将output视为:

[10 (seq_length), 1 (batch),  2 (num_directions), 100 (hidden_size)]

字符串
然后,正向方向上的最后一个输出将是output[9][0][0],反向方向上的最后一个输出将是output[0][0][1]
我希望这能澄清一些事情。

相关问题