PyTorch实现字符级LSTM文本生成时训练损失无变化问题求助
问题原因及修复方案
核心错误点
- 每个字符步重复初始化LSTM隐状态
你在循环处理每个字符的代码里,每次都调用model.init_hidden()重置隐状态,直接破坏了LSTM的时序记忆能力,模型无法学习到字符之间的序列依赖关系,相当于每次都只根据当前单个字符预测下一个字符,完全没有用到上下文信息。隐状态只需要在每个完整序列输入前初始化一次即可。 - 损失函数和输出层搭配错误
PyTorch的nn.CrossEntropyLoss()内置了Softmax计算逻辑,你在模型最后一层手动加了nn.Softmax(dim=1),相当于对输出做了两次Softmax变换,会导致梯度被大幅压缩,模型参数更新幅度极小,损失自然几乎没有变化。 - 单epoch训练样本量不足
你每个epoch只随机采样1个batch的数据进行训练,模型能见到的样本量太少,无法学习到足够的分布规律。
修复方案
- 修改模型定义,移除最后一层Softmax:
# 删掉self.o = nn.Softmax(dim=1)这一行,forward里也删掉out = self.o(out) def forward(self, x, hidden, cell): out = self.embed(x) out = self.dropout(out) out, (hidden, cell) = self.lstm(out.unsqueeze(1), (hidden, cell)) out = self.fc(out.reshape(out.shape[0], -1)) # 移除softmax层,直接输出fc结果给CrossEntropyLoss return out, (hidden, cell)
- 调整训练函数的隐状态初始化逻辑,同时增加每个epoch的训练batch数:
def train(model, optimizer, criterion, epochs=10, every=5): for epoch in range(epochs): mean_loss = 0 # 每个epoch遍历多个batch,这里示例遍历所有数据,可根据实际情况调整 total_batch = len(data) // seq_len # seq_len是你单序列的长度 for batch_idx in range(total_batch): x, y = get_batch(batch_idx * seq_len) xt, yt = tensorize(x,y) L = len(xt) # 每个序列开始前只初始化一次隐状态 hidden, cell = model.init_hidden(batch_size) for i in range(L): out, (hidden, cell) = model(xt[i].unsqueeze(0), hidden, cell) target = yt[i].unsqueeze(0) loss = criterion(out, target) loss.backward() optimizer.step() optimizer.zero_grad() mean_loss += loss.item() if epoch % every == 0: print("epoch = ", epoch ," mean loss = ", mean_loss/(total_batch*L))
内容的提问来源于stack exchange,提问作者mac179
相关产品推荐
相关产品推荐

