您对大多数概念的理解是准确的,但是,这里和那里都有一些缺失点。
接口嵌入到LSTM(或任何其他经常性装置)
将输出嵌入为
(batch_size, seq_len, embedding_size)
。现在,有多种方法可以将其传递给LSTM。
*您可以将其直接传递给
LSTM
如果
LSTM公司
接受输入为
batch_first
。因此,在创建
LSTM公司
pass参数
batch_first=True
。
*或者,您可以以以下形状传递输入
(seq_len, batch_size, embedding_size)
。因此,要将嵌入输出转换为该形状,需要使用
torch.transpose(tensor_name, 0, 1)
,就像你提到的。
Q、 我在网上看到了许多类似于x=嵌入的示例。视图(len(句子),self。batch\u size,-1),这让我很困惑。
A、 这是错误的。它会混淆批次,你将试图学习一项毫无希望的学习任务。无论您在哪里看到这一点,都可以告诉作者更改此语句,并改用转置。
有一种观点支持不使用
第一批\u
,这说明Nvidia CUDA提供的底层API使用批处理作为辅助程序运行速度要快得多。
使用上下文大小
您直接将嵌入输出提供给LSTM,这将把LSTM的输入大小固定为上下文大小1。这意味着,如果您的输入是LSTM的单词,那么您将始终一次给它一个单词。但是,这不是我们一直想要的。因此,需要扩展上下文大小。可按如下方式进行-
embeds = embeds.unfold(1, context_size, 1) # Keeping the step size to be 1
embeds = embeds.view(embeds.size(0), embeds.size(1), -1)
Unfold documentation
现在,您可以如上所述继续将其提供给
LSTM公司
,记住了
seq_len
现在更改为
seq_len - context_size + 1
和
embedding_size
(是LSTM的输入大小)现在更改为
context_size * embedding_size
使用可变序列长度
批处理中不同实例的输入大小并不总是相同的。例如,您的句子中有些可能有10个单词长,有些可能有15个,有些可能有1000个。所以,你肯定想要可变长度的序列输入到你的循环单位。要做到这一点,在将输入反馈到网络之前,需要执行一些额外的步骤。您可以按照以下步骤操作-
1、将批次从最大顺序排序到最小顺序。
2、创建
seq_lengths
定义批次中每个序列长度的数组。(这可以是一个简单的python列表)
3、填充所有序列,使其与最大序列的长度相等。
4、创建该批次的LongTensor变量。
现在,在通过嵌入和创建适当的上下文大小输入传递上述变量之后,您需要按如下方式打包您的序列-
lstm_input = nn.utils.rnn.pack_padded_sequence(embeds, [x - context_size + 1 for x in seq_lengths], batch_first=False)
了解LSTM的输出
现在,一旦你准备好
lstm_input
根据您的需要,您可以将lstm称为
lstm_outs, (h_t, h_c) = lstm(lstm_input, (h_t, h_c))
在这里
(h_t, h_c)
需要作为初始隐藏状态提供,它将输出最终隐藏状态。您可以看到,为什么需要打包可变长度序列,否则LSTM也会在非必需的填充词上运行。
现在
lstm_outs
将是一个压缩序列,它是lstm在每个步骤的输出,并且
(h\u t,h\u c)
分别是最终输出和最终单元状态。
h_t
和
h_c
将成形
(batch_size, lstm_size)
。您可以直接将其用于进一步的输入,但如果您还想使用中间输出,则需要解压缩
lstm\U输出
首先如下所示
lstm_outs, _ = nn.utils.rnn.pad_packed_sequence(lstm_outs)
现在,你的
lstm\U输出
将成形
(max_seq_len - context_size + 1, batch_size, lstm_size)
。现在,您可以根据需要提取lstm的中间输出。
请记住,未打包的输出在每个批的大小之后将有0,这只是填充以匹配最大序列的长度(它总是第一个序列,因为我们将输入从最大到最小排序)。
还要注意,对于每个批次输出,h\u t始终等于最后一个元素。
将lstm连接到线性
现在,如果只想使用lstm的输出,可以直接馈送
h\U t
到你的线性层,它会工作。但是,如果您还想使用中间输出,那么您需要弄清楚,如何将其输入到线性层(通过一些注意网络或池)。您不想将完整的序列输入到线性层,因为不同的序列具有不同的长度,并且您无法固定线性层的输入大小。是的,您需要转置lstm的输出以进一步使用(同样,您不能在这里使用view)。
结束语:我特意留下了一些要点,例如使用双向循环单元格、在“展开”中使用步长以及界面注意,因为它们可能会变得非常繁琐,超出了本答案的范围。