了解用于序列分类的 LSTM 架构

Posted

技术标签:

【中文标题】了解用于序列分类的 LSTM 架构【英文标题】:Understanding the architecture of an LSTM for sequence classification 【发布时间】:2021-11-15 12:24:26 【问题描述】:

我在 pytorch 中有这个模型,一直用于序列分类。

class RoBERT_Model(nn.Module):

    def __init__(self, hidden_size = 100):
        self.hidden_size = hidden_size
        super(RoBERT_Model, self).__init__()
        self.lstm = nn.LSTM(768, hidden_size, num_layers=1, bidirectional=False)
        self.out = nn.Linear(hidden_size, 2)

    def forward(self, grouped_pooled_outs):
        # chunks_emb = pooled_out.split_with_sizes(lengt) # splits the input tensor into a list of tensors where the length of each sublist is determined by length

        seq_lengths = torch.LongTensor([x for x in map(len, grouped_pooled_outs)]) # gets the length of each sublist in chunks_emb and returns it as an array

        batch_emb_pad = nn.utils.rnn.pad_sequence(grouped_pooled_outs, padding_value=-91, batch_first=True) # pads each sublist in chunks_emb to the largest sublist with value -91
        batch_emb = batch_emb_pad.transpose(0, 1)  # (B,L,D) -> (L,B,D)
        lstm_input = nn.utils.rnn.pack_padded_sequence(batch_emb, seq_lengths, batch_first=False, enforce_sorted=False) # seq_lengths.cpu().numpy()

        packed_output, (h_t, h_c) = self.lstm(lstm_input, )  # (h_t, h_c))
        # output, _ = nn.utils.rnn.pad_packed_sequence(packed_output, padding_value=-91)
        h_t = h_t.view(-1, self.hidden_size) # (-1, 100)

        return self.out(h_t) # logits

我遇到的问题是我并不完全相信哪些数据正在传递到最终分类层。我相信正在做的是只有最后一层中的最终 LSTM 单元用于分类。也就是说,有hidden_size 特征被传递到前馈层。

我在此图中描绘了我认为发生的事情:

这种理解正确吗?我错过了什么吗?

谢谢。

【问题讨论】:

【参考方案1】:

您的代码是用于分类的基本 LSTM,使用单个 rnn 层。

在您的图片中,您有多个 LSTM 层,而实际上,图片中只有一个 H_n^0

    您对 LSTM 的输入的形状为 (B, L, D),正如评论中正确指出的那样。 packed_outputh_c 根本没有使用,因此您可以将此行更改为:_, (h_t, _) = self.lstm(lstm_input) 以免进一步混淆图片 h_t每个批处理元素的最后一步的输出,通常是(B, D * L, hidden_size)。因为这个神经网络不是双向的D=1,因为你也有一个单层L=1,所以输出的形状是(B, 1, hidden_size)。 此输出被重新整形为nn.Linear 兼容(此行:h_t = h_t.view(-1, self.hidden_size)),并将为您提供形状为(B, hidden_size) 的输出 此输入被馈送到单个nn.Linear 层。

一般来说,RNN 的最后一个时间步的输出用于批次中的每个元素,在您的图片H_n^0 中,并简单地馈送到分类器。

顺便说一句,在分类中使用self.out = nn.Linear(hidden_size, 2) 可能会适得其反;很可能您正在执行二进制分类,并且可能会使用 self.out = nn.Linear(hidden_size, 1)torch.nn.BCEWithLogitsLoss。单个logit包含标签应该是0还是1的信息;根据 nn,小于0 的所有内容都更有可能是0,大于0 的所有内容都被视为1 标签。

【讨论】:

抱歉,照片/代码对可能有点误导。虚线应该表示可能有 1 到 (W-1) 层数。所以为了澄清,假设我使用了 5 个 lstm 层。这意味着只有H_n^4 会(并且应该)被馈送到分类器,对吗? 也感谢关于仅使用 1 个神经元进行二元分类的说明。作为一个附带问题,通常对于 n > 2 的 n 元分类,我们应该有 n 个输出神经元,对吧? @LucaGuarro 是的,在这种情况下应该馈送最后一层 H_n^4(尽管它需要一些代码更改,请查看文档以获取输出的确切描述)。附带问题 - 是的,对于多类,您将使用 CrossEntropy,对于多标签 BCE,但仍然是 n 个输出。

以上是关于了解用于序列分类的 LSTM 架构的主要内容,如果未能解决你的问题,请参考以下文章

使用 LSTM Keras 的序列数据进行多类分类不起作用

用LSTM分类 MNIST

LSTM 时间序列分类

使用(?) LSTM 进行多变量时间序列分类

TFLearn LSTM 时间序列分类

在 LSTM 中包含分类特征和序列以进行序列预测的最佳实践?