【问题标题】:LSTM error: AttributeError: 'tuple' object has no attribute 'dim'LSTM 错误:AttributeError:'tuple' 对象没有属性'dim'
【发布时间】:2023-12-07 00:43:02
【问题描述】:

我有以下代码:

import torch
import torch.nn as nn

model = nn.Sequential(
          nn.LSTM(300, 300),
          nn.Linear(300, 100),
          nn.ReLU(),
          nn.Linear(300, 7),
          )

s = torch.ones(1, 50, 300)
a = model(s)

我得到:

My-MBP:Desktop myname$ python3 testmodel.py 
Traceback (most recent call last):
  File "testmodel.py", line 12, in <module>
    a = model(s)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/torch/nn/modules/module.py", line 727, in _call_impl
    result = self.forward(*input, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/torch/nn/modules/container.py", line 117, in forward
    input = module(input)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/torch/nn/modules/module.py", line 727, in _call_impl
    result = self.forward(*input, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/torch/nn/modules/linear.py", line 93, in forward
    return F.linear(input, self.weight, self.bias)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/torch/nn/functional.py", line 1688, in linear
    if input.dim() == 2 and bias is not None:
AttributeError: 'tuple' object has no attribute 'dim'

为什么?尺寸应该没问题。当*inputmodel.forward 中定义时,我看到了针对此问题的相关修复,但我什至还没有实现任何东西。

/edit: 等等,有*input!?我怎样才能覆盖它?

【问题讨论】:

  • 这个错误是因为 LSTM 的输出是一个包含输出、隐藏状态和单元状态的元组。您不能将其传递给线性层。你应该只传递 LSTM 的输出,而不是隐藏和单元状态。

标签: python pytorch lstm


【解决方案1】:

您将无法在nn.Sequential 中使用nn.RNN,因为nn.LSTM 层将输出一个包含(1) 输出特征的元组 (2) 隐藏状态和单元状态。

必须首先解压缩输出才能在后续层中使用输出功能:nn.Linear。例如,如果您对隐藏状态和单元状态感兴趣:

rnn = nn.LSTM(300, 300)
output, (h_n, c_n) = rnn(x)

您可以定义一个自定义nn.Module 并实现一个简单的转发功能:

class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()

        self.rnn = nn.LSTM(300, 300)
        
        self.body = nn.Sequential(
          nn.Linear(300, 100),
          nn.ReLU(),
          nn.Linear(100, 7)) # <- had it set to in_features=300

    def forward(self, x):
        x, _ = self.rnn(x) # <- ignore second output
        x = self.body(x)
        return x

这样:

>>> model = Model()
>>> s = torch.ones(1, 50, 300)

>>> model(s).shape
torch.Size([1, 50, 7])

【讨论】:

  • 谢谢!我知道我有三个输出,但不知何故我没想到这可能会导致麻烦。快速跟进问题:我想使用编码器架构进行文本分类。我的[1, 50, 300] 是一个长度为50 的句子,其中每个单词都嵌入了维度300。编码后的序列将被传递到 FC 层。我是否只取 lstm 张量的最后“行”并通过它?,即(不是很漂亮):rnn(s)[0][-1][-1].reshape(1,1,300)
  • 如果1 是您的批量大小,那么您肯定需要在nn.LSTM 上设置batch_first=True。因此,您的 RNN 输出将是 (batch, seq_len, input_size, hidden_size),在您的情况下为:(1, 50, 300)。使用rnn(s)[0][-1][-1] 将选择最后一个批处理元素的最后一个时间步长的预测。而是使用rnn(s)[0][:, -1]。更简洁的方法 (imo) 是先解包(上面的 c.f)然后从第一个 tuple 元素中获取 [:, -1]
【解决方案2】:

错误是因为nn.LSTM 返回了你的输出和你的模型的状态,这是一个包含隐藏状态和记忆状态的元组。

您可以通过定义自己的 nn.Module 类来修复它,该类只为您返回 LSTM 的输出。

class GetLSTMOutput(nn.Module):
    def forward(self, x):
        out, _ = x
        return out

model = nn.Sequential(
    nn.LSTM(300, 300),
    GetLSTMOutput(),
    nn.Linear(300, 100),
    nn.ReLU(),
    nn.Linear(300, 7))

GetLSTMOutput 类的 forward 方法被隐式调用,上一层的输出nn.LSTM(300, 300) 作为参数传递。然后它只返回输出部分,丢弃模型的状态。

【讨论】: