PyTorch LSTM二分类文本分类模型训练无提升问题求助
类别不平衡问题
损失稳定在0.7左右(接近-ln(0.5)≈0.693)且只预测0类,最常见的原因是训练集里0类样本占比极高。模型会通过偏向多数类来最小化损失,此时即使随机预测多数类也能得到“看似合理”的损失,但完全没有学习到有效特征。
解决:统计训练集中两类样本的数量,若存在不平衡,可采用过采样少数类、欠采样多数类,或使用带权重的损失函数(比如BCELoss(weight=class_weights),class_weights根据类别占比计算)。模型输出与损失函数不匹配
你的代码存在关键矛盾:二分类场景下,若使用BCELoss,模型最后一层应输出1个神经元(对应样本属于正类的概率),但如果num_classes设为2,fc层会输出2维向量,再经过sigmoid后每个维度都是0-1的概率,这和BCELoss的预期输入不匹配(BCELoss要求输入和目标形状一致,且目标是单维度的0/1标签)。
同时,手动加sigmoid再用BCELoss的数值稳定性不如直接用BCEWithLogitsLoss(该损失函数内部计算sigmoid,避免梯度消失)。
解决:- 若坚持用
sigmoid+BCELoss:将num_classes改为1,fc层输出设为1维,同时确保标签labels是float类型且形状为(batch_size, 1)或(batch_size,)。 - 更推荐的方式:去掉模型中的
torch.sigmoid(out),改用BCEWithLogitsLoss作为损失函数,同样将num_classes设为1。 - 若想用2维输出,应使用
CrossEntropyLoss,此时模型最后一层不需要激活函数,标签labels应为long类型的类别索引(0或1)。
- 若坚持用
序列最后时间步输出的有效性问题
代码中取out[:, -1]作为LSTM的输出喂给全连接层,但如果输入序列经过padding(padding_idx=0),最后一个位置很可能是填充的0 token,对应的embedding是全0向量,LSTM在该位置的输出不包含有效语义信息,导致模型无法学习到有用特征。
解决:- 改用LSTM的隐藏状态输出:
out, (h_n, c_n),取h_n[-1](最后一层的隐藏状态)作为全连接层的输入,LSTM的隐藏状态是对整个序列的编码,比最后一个时间步的输出更可靠。 - 记录每个序列的有效长度,取有效长度对应的最后一个时间步的输出,而非固定取最后一个位置。
- 改用LSTM的隐藏状态输出:
数据预处理与输入有效性问题
检查以下几点:- 确认输入序列
sequences不是全0向量(比如tokenization错误,所有文本都被映射为0),可随机打印几个样本的序列值验证。 - 确认标签
labels的类型是float(BCELoss要求目标是浮点型),若为long类型会导致损失计算异常。 - 检查词汇表大小
vocabulary_size是否正确,若设置过小,会导致大量token被映射为未知token(通常是0或其他特殊值),影响embedding的有效性。
- 确认输入序列
学习率与初始化问题
虽你调整过学习率,但仍需确认:- 学习率是否过高或过低:过高会导致损失震荡,过低则模型学习缓慢甚至停滞,可尝试
1e-4到1e-3的范围测试。 - 是否使用预训练词向量:随机初始化的embedding在小数据集上可能难以收敛,若有合适的预训练词向量(如Word2Vec、GloVe),可加载到embedding层,冻结或微调该层。
- 学习率是否过高或过低:过高会导致损失震荡,过低则模型学习缓慢甚至停滞,可尝试
内容的提问来源于stack exchange,提问作者Martina

