了解用于序列分类的 LSTM 架构
Understanding the architecture of an LSTM for sequence classification
我在 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
个特征被传递到前馈层。
我在这里描述了我认为在这个图中发生的事情:
这个理解对吗?我错过了什么吗?
谢谢。
您的代码是用于分类的基本 LSTM,使用单个 rnn 层。
在你的图片中你有多个 LSTM 层,而实际上只有一个,图片中 H_n^0
。
- 您对 LSTM 的输入具有评论中正确指出的
(B, L, D)
形状。
packed_output
和 h_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
标签。
我在 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
个特征被传递到前馈层。
我在这里描述了我认为在这个图中发生的事情:
这个理解对吗?我错过了什么吗?
谢谢。
您的代码是用于分类的基本 LSTM,使用单个 rnn 层。
在你的图片中你有多个 LSTM 层,而实际上只有一个,图片中 H_n^0
。
- 您对 LSTM 的输入具有评论中正确指出的
(B, L, D)
形状。 packed_output
和h_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
标签。