PyTorch简易RNN训练报错:RuntimeError维度不匹配求助
PyTorch RNN序列预测报错:RuntimeError 解决方案
错误详情
运行RNN训练代码时触发如下错误:
RuntimeError: For unbatched 2-D input, hx should also be 2-D but got 3-D tensor
错误原因
定义RNN时设置了batch_first=True,要求输入张量形状为**(批量大小, 序列长度, 输入特征数),但当前输入数据X_train/X_test是2维张量(样本数, T),缺少了输入特征维度(这里输入特征数为1)。PyTorch将这种2维输入判定为无批量的输入**(即把第一维度当成序列长度,第二维度当成输入特征数),但我们初始化的隐藏状态h0是3维张量(层数, 批量大小, 隐藏层大小),两者维度不匹配,导致报错。
修复方案
给输入数据添加输入特征维度,将形状从(N, T)调整为(N, T, 1),有两种实现方式:
方式1:在Numpy数据预处理阶段修改
将数据集构建后的X reshape代码修改为:
X = np.array(X).reshape(-1, T, 1) # 新增最后一个维度对应输入特征数1
方式2:在转换为PyTorch Tensor后修改
在生成X_train和X_test后添加维度扩展:
X_train = torch.from_numpy(X[:-N//2].astype(np.float32)).unsqueeze(-1) X_test = torch.from_numpy(X[-N//2:].astype(np.float32)).unsqueeze(-1)
完整修正代码
import torch import torch.nn as nn import numpy as np import matplotlib.pyplot as plt # 生成原始数据 N = 1000 series = np.sin(0.1 * np.arange(N)) # 可添加噪声:+ np.random.randn(N)*0.1 # 可视化数据 plt.plot(series) plt.show() # 构建数据集 T = 10 # 用前10个时间步预测下一个时间步 X = [] Y = [] for t in range(len(series) - T): x = series[t:t+T] X.append(x) y = series[t+T] Y.append(y) # 调整X的形状为(样本数, 序列长度, 输入特征数) X = np.array(X).reshape(-1, T, 1) Y = np.array(Y).reshape(-1, 1) N = len(X) print("X.shape", X.shape, "Y.shape", Y.shape) # 设置计算设备 device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") print(device) # 定义简易RNN模型 class simpleRNN(nn.Module): def __init__(self, n_inputs, n_hidden, n_rnnlayers, n_outputs): super(simpleRNN,self).__init__() self.D = n_inputs self.M = n_hidden self.K = n_outputs self.L = n_rnnlayers self.rnn = nn.RNN( input_size=self.D, hidden_size=self.M, num_layers=self.L, nonlinearity='relu', batch_first=True ) self.fc = nn.Linear(self.M, self.K) def forward(self, X): # 初始化隐藏状态 h0 = torch.zeros(self.L, X.size(0), self.M).to(device) # 获取RNN输出 out, _ = self.rnn(X, h0) # 取最后一个时间步的输出传入全连接层 out = self.fc(out[:, -1, :]) return out # 实例化模型 model = simpleRNN(n_inputs=1, n_hidden=5, n_rnnlayers=1, n_outputs=1) model.to(device) # 定义损失函数和优化器 criterion = nn.MSELoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.1) # 转换数据为Tensor并移动到设备 X_train = torch.from_numpy(X[:-N//2].astype(np.float32)).to(device) Y_train = torch.from_numpy(Y[:-N//2].astype(np.float32)).to(device) X_test = torch.from_numpy(X[-N//2:].astype(np.float32)).to(device) Y_test = torch.from_numpy(Y[-N//2:].astype(np.float32)).to(device) # 训练函数 def full_gd(model, criterion, optimizer, X_train, Y_train, X_test, Y_test, epochs=200): train_losses = np.zeros(epochs) test_losses = np.zeros(epochs) for i in range(epochs): optimizer.zero_grad() # 前向传播 outputs = model(X_train) loss = criterion(outputs, Y_train) # 反向传播与优化 loss.backward() optimizer.step() # 记录损失 train_losses[i] = loss.item() # 计算测试损失 test_outputs = model(X_test) test_loss = criterion(test_outputs, Y_test) test_losses[i] = test_loss.item() if (i+1) % 5 == 0: print(f"Epoch {i+1}/{epochs}, Train_loss: {loss.item():.4f}, Test_loss: {test_loss.item():.4f}") return train_losses, test_losses # 启动训练 train_losses, test_losses = full_gd(model, criterion, optimizer, X_train, Y_train, X_test, Y_test)
内容的提问来源于stack exchange,提问作者CMDTAUSIF
相关产品推荐
相关产品推荐

