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 ---> 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维是缺少了批量、序列长度维度导致的,按以下步骤修改即可:
- 补全输入维度
在训练循环和验证循环的text = batch["Sample"].to(device)代码后,补全缺失的维度:
# 补全序列长度维度,单时间步场景下序列长度为1 text = text.unsqueeze(1) # 如果DataLoader没有自动补全批量维度,再加下面这行 # text = text.unsqueeze(0)
- 修复验证阶段返回值解包错误
模型返回两个参数(output, hidden),需要把验证阶段的output = model(text)改为output, _ = model(text),避免解包报错。 - 隐藏状态设备对齐
修改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
相关产品推荐
相关产品推荐

