为何我的LSTM模型无法判断序列中1的数量奇偶性?
问题分析与修正方案
你的任务是序列奇偶校验(判断序列中1的个数奇偶性),本质是让模型学习累积计数的奇偶特征,当前训练准确率低主要源于网络结构设计、训练参数设置的不合理,具体修正点如下:
1. 错误使用LSTM输出特征
你的任务只需要LSTM最后一个时间步的隐藏状态——因为奇偶性是整个序列的累积结果,最后一个状态已经包含了前面所有元素的信息。但你当前把所有时间步的隐藏状态(形状(1,5,10))展平后输入全连接层,这会引入大量冗余信息,干扰模型学习核心逻辑。
修正方式:
修改forward方法,仅提取最后一个时间步的输出,并对应调整全连接层输入维度:
class LSTMNet(nn.Module): def __init__(self): super().__init__() self.hidden_size = 10 self.lstm = nn.LSTM(input_size=1, hidden_size=self.hidden_size, num_layers=1, batch_first=True) # 去掉Flatten,输入维度改为hidden_size self.net = nn.Sequential( nn.ReLU(), nn.Linear(self.hidden_size, 1), nn.Sigmoid() ) def forward(self, x): x, _ = self.lstm(x) # 取最后一个时间步的hidden state x = self.net(x[:, -1, :]) return x
2. 训练参数设置不合理
- 学习率与优化器选择:SGD用
0.001的学习率对于这个简单任务来说太小,梯度更新极慢。建议换成自适应学习率的Adam优化器,或把SGD学习率调到0.01以上:optimizer = torch.optim.Adam(model.parameters(), lr=0.001) - Batch Size过小:
batch_size=1会导致梯度更新极度不稳定,噪声极大,模型难以学到稳定特征。建议把batch size调到32或64:training_loader = DataLoader(trainingSet, batch_size=32, shuffle=True) validation_loader = DataLoader(testSet, batch_size=32, shuffle=False) - 训练轮数不足:10轮训练对于LSTM来说太少,至少训练50-100轮,观察准确率收敛趋势。
3. 标签形状的严谨性修正
在LSTMDataset的__getitem__中,label.reshape((1))得到的是(1,)形状的张量,而模型输出是(1,1),虽然BCELoss会自动广播,但统一形状能避免潜在问题:
def __getitem__(self, idx): sample, label = self.x[idx], self.y[idx] return sample.reshape((-1, 1)), label.reshape((1, 1))
4. 可选:简化网络结构
这个任务非常简单,不需要两层LSTM,单层LSTM(num_layers=1)就足够完成任务,减少模型复杂度反而更容易收敛。
修正后训练核心代码示例
if __name__ == "__main__": # 数据生成部分保持不变 numSamples = 1000 sampleLength = 5 samples = np.ndarray( shape=( numSamples, sampleLength ), dtype=np.float32 ) labels = np.ndarray( shape=( numSamples ), dtype=np.float32 ) for s in range( numSamples ): sample = np.random.choice( [ 0, 1 ], size=sampleLength ) samples[ s ] = sample even = np.count_nonzero( sample == 1 ) % 2 == 0 labels[ s ] = int( even ) X_train, X_test, y_train, y_test = train_test_split( samples, labels, test_size=0.25, random_state=42 ) trainingSet = LSTMDataset( X_train, y_train ) testSet = LSTMDataset( X_test, y_test ) # 调整batch size training_loader = DataLoader(trainingSet, batch_size=32, shuffle=True) validation_loader = DataLoader(testSet, batch_size=32, shuffle=False) model = LSTMNet() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) loss_fn = torch.nn.BCELoss() # 增加训练轮数 for epoch in range(50): yPredicted = [] yTruth = [] model.train() for i, data in enumerate(training_loader): inputs, labels = data optimizer.zero_grad() outputs = model(inputs) loss = loss_fn(outputs, labels) loss.backward() optimizer.step() # 批量处理标签与预测结果 yTruth.extend(labels.cpu().numpy().flatten().astype(int)) yPredicted.extend(torch.round(outputs).cpu().numpy().flatten().astype(int)) accuracy = accuracy_score(yTruth, yPredicted) print(f"Epoch {epoch+1}, Accuracy: {accuracy:.2f}")
内容的提问来源于stack exchange,提问作者binaryBigInt
相关产品推荐
相关产品推荐

