You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyTorch RNN训练报错RuntimeError:输入需3维实际为1维问题求助

问题描述

我参考公开教程的代码训练RNN模型,也找到了两个相似的相关帖子,但没能从中推断出问题的修复方案。
报错含义很明确:模型预期输入为3维,但实际传入的是1维输入,我不知道应该在哪里修复该问题。
我的输入是300维词向量,输出是长度为11的独热编码向量,模型需要在11个输出维度上做分类选择。

数据加载器代码

from torch.utils.data import Dataset, DataLoader

class CustomDataset(Dataset):
    def __init__(self, dat, labels):
        self.labels = labels
        self.dat = dat

    def __len__(self):
        return len(self.labels)
    
    def __getitem__(self, idx):
        label = self.labels[idx]
        dat = self.dat[idx]
        sample = {"Sample": dat, "Class": label}
        return sample

Vanilla RNN模型定义

class VanillaRNN(nn.Module):
    def __init__(self, input_size, output_size, hidden_dim, n_layers):
        super(VanillaRNN, self).__init__()

        # 定义参数
        self.hidden_dim = hidden_dim
        self.n_layers = n_layers

        # 定义层
        # RNN层
        self.rnn = nn.RNN(input_size, hidden_dim, n_layers, batch_first=True)   
        # 全连接层
        self.fc = nn.Linear(hidden_dim, output_size)
    
    def forward(self, inputs):
        
        batch_size = inputs.size(0)

        # 调用下方定义的方法初始化首个输入的隐藏状态
        hidden = self.init_hidden(batch_size)

        # 输入和隐藏状态传入模型获取输出
        out, hidden = self.rnn(inputs, hidden)
        
        # 重塑输出适配全连接层输入要求
        out = out.contiguous().view(-1, self.hidden_dim)
        out = self.fc(out)
        
        return out, hidden
    
    def init_hidden(self, batch_size):
        # 该方法生成前向传播使用的初始零值隐藏状态
        # 我们会将隐藏状态张量发送到之前指定的设备上
        hidden = torch.zeros(self.n_layers, batch_size, self.hidden_dim)
        return hidden

训练循环代码

def plot_train_val(x, train, val, train_label,
                   val_label, title, y_label,
                   color):

  plt.plot(x, train, label=train_label, color=color)
  plt.plot(x, val, label=val_label, color=color, linestyle='--')
  plt.legend(loc='lower right')
  plt.xlabel('epoch')
  plt.ylabel(y_label)
  plt.title(title)


def count_parameters(model):
  parameters = sum(p.numel() for p in model.parameters() if p.requires_grad)
  return parameters


def init_weights(m):
  if type(m) in (nn.Linear, nn.Conv1d):
    nn.init.xavier_uniform_(m.weight)



# 训练函数
def train(model, device, train_loader, valid_loader, epochs, learning_rate):

  criterion = nn.CrossEntropyLoss()
  optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
  
  train_loss, validation_loss = [], []
  train_acc, validation_acc = [], []

  for epoch in range(epochs):
    # 训练阶段
    model.train()
    running_loss = 0.
    correct, total = 0, 0
    steps = 0
    for idx, batch in enumerate(train_loader):
      text = batch["Sample"].to(device)
      target = batch['Class'].to(device)
      target = torch.autograd.Variable(target).long()
      text, target = text.to(device), target.to(device)
      # 训练循环逻辑
      optimizer.zero_grad()
      output, hideden = model(text)
      print(output.shape, target.shape, target.view(-1).shape)
      loss = criterion(output, target.view(-1))
      loss.backward()
      optimizer.step()
      steps += 1
      running_loss += loss.item()

      # 计算准确率
      _, predicted = torch.max(output, 1)
      print(predicted)
      #predicted = torch.round(output.squeeze())
      total += target.size(0)
      correct += (predicted == target).sum().item()

    train_loss.append(running_loss/len(train_loader))
    train_acc.append(correct/total)

    print(f'Epoch: {epoch + 1}, 'f'Training Loss: {running_loss/len(train_loader):.4f}, 'f'Training Accuracy: {100*correct/total: .2f}%')

    # 验证集评估
    model.eval()
    running_loss = 0.
    correct, total = 0, 0

    with torch.no_grad():
      for idx, batch in enumerate(valid_loader):
        text = batch["Sample"].to(device)
        print(type(text), text.shape)
        target = batch['Class'].to(device)
        target = torch.autograd.Variable(target).long()
        text, target = text.to(device), target.to(device)

        optimizer.zero_grad()
        output = model(text)
        
        loss = criterion(output, target)
        running_loss += loss.item()

        # 计算准确率
        _, predicted = torch.max(output, 1)
        #predicted = torch.round(output.squeeze())
        total += target.size(0)
        correct += (predicted == target).sum().item()

    validation_loss.append(running_loss/len(valid_loader))
    validation_acc.append(correct/total)

    print (f'Validation Loss: {running_loss/len(valid_loader):.4f}, 'f'Validation Accuracy: {100*correct/total: .2f}%')

  return train_loss, train_acc, validation_loss, validation_acc

训练启动代码

# 模型超参数
#vocab_size = len(word_array)
learning_rate = 1e-3
output_size = 11
input_size = 300
epochs = 10
hidden_dim = 100
n_layers = 2

# 初始化模型、训练与测试流程
set_seed(SEED)
vanilla_rnn_model = VanillaRNN(input_size, output_size, hidden_dim, n_layers)

#vanilla_rnn_model = VanillaRNN(output_size, input_size, RNN_size, fc_size, DEVICE)
vanilla_rnn_model.to(DEVICE)

vanilla_rnn_start_time = time.time()
vanilla_train_loss, vanilla_train_acc, vanilla_validation_loss, vanilla_validation_acc = train(vanilla_rnn_model, DEVICE, train_loader, valid_loader, epochs = epochs, learning_rate = learning_rate)

报错信息

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-31-bfd2f8f3456f> in <module>()
     19                                                                                                valid_loader,
     20                                                                                                epochs = epochs,
---> 21                                                                                                learning_rate = learning_rate)
     22 print("--- Time taken to train = %s seconds ---" % (time.time() - vanilla_rnn_start_time))
     23 #test_accuracy = test(vanilla_rnn_model, DEVICE, test_iter)

6 frames
<ipython-input-30-db1fa6c8b625> in train(model, device, train_loader, valid_loader, epochs, learning_rate)
     45       # add micro for coding training loop
     46       optimizer.zero_grad()
---> 47       output, hideden = model(text)
     48       print(output.shape, target.shape, target.view(-1).shape)
     49       loss = criterion(output, target.view(-1))

/usr/local/lib/python3.7/dist-packages/torch/nn/modules/module.py in _call_impl(self, *input, **kwargs)
   1049         if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
   1050                 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1051             return forward_call(*input, **kwargs)
   1052         # Do not call functions when jit is used
   1053         full_backward_hooks, non_full_backward_hooks = [], []

<ipython-input-26-c34b90b3cbc3> in forward(self, x)
     21 
     22         # Passing in the input and hidden state into the model and obtaining outputs
---&gt; 23         out, hidden = self.rnn(x, hidden)
     24 
     25         # Reshaping the outputs such that it can be fit into the fully connected layer

/usr/local/lib/python3.7/dist-packages/torch/nn/modules/rnn.py in forward(self, input, hx)
    263         assert hx is not None
    264         input = cast(Tensor, input)
---> 265         self.check_forward_args(input, hx, batch_sizes)
    266         _impl = _rnn_impls[self.mode]
    267         if batch_sizes is None:

/usr/local/lib/python3.7/dist-packages/torch/nn/modules/rnn.py in check_forward_args(self, input: Tensor, hidden: Tensor, batch_sizes: Optional[Tensor]):
    227 
    228     def check_forward_args(self, input: Tensor, hidden: Tensor, batch_sizes: Optional[Tensor]):
---> 229         self.check_input(input, batch_sizes)
    230         expected_hidden_size = self.get_expected_hidden_size(input, batch_sizes)
    231 

/usr/local/lib/python3.7/dist-packages/torch/nn/modules/rnn.py in check_input(self, input, batch_sizes)
    201             raise RuntimeError(
    202                 'input must have {} dimensions, got {}'.format(
---> 203                     expected_input_dim, input.dim()))
    204         if self.input_size != input.size(-1):
    205             raise RuntimeError(

RuntimeError: input must have 3 dimensions, got 1

修复方案

PyTorch的RNN层在batch_first=True配置下,要求输入张量形状为(批量大小, 序列长度, 特征维度)三个维度,你当前输入只有1维是缺少了批量、序列长度维度导致的,按以下步骤修改即可:

  1. 补全输入维度
    在训练循环和验证循环的text = batch["Sample"].to(device)代码后,补全缺失的维度:
# 补全序列长度维度,单时间步场景下序列长度为1
text = text.unsqueeze(1)
# 如果DataLoader没有自动补全批量维度,再加下面这行
# text = text.unsqueeze(0)
  1. 修复验证阶段返回值解包错误
    模型返回两个参数(output, hidden),需要把验证阶段的output = model(text)改为output, _ = model(text),避免解包报错。
  2. 隐藏状态设备对齐
    修改init_hidden方法,把隐藏状态放到和输入一致的设备上:
def init_hidden(self, batch_size, device):
    hidden = torch.zeros(self.n_layers, batch_size, self.hidden_dim).to(device)
    return hidden

同时在forward方法调用初始化时传入设备:

hidden = self.init_hidden(batch_size, inputs.device)

内容的提问来源于stack exchange,提问作者Aswiderski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 21:45:04