Pytorch逻辑回归图像分类训练损失为负不收敛,是否参数未更新?
训练异常问题排查结果
已定位的代码硬伤
- 模型结构冗余且不符合逻辑回归定义
标准逻辑回归的二分类输出逻辑为:线性层输出 → Sigmoid激活输出0-1区间的预测值。当前代码在Sigmoid层后额外添加的ReLU层属于完全冗余的设计:Sigmoid的输出范围本身就在(0,1)区间,ReLU(取正数部分)对这个范围的输入没有任何调整作用,属于无效代码。 - 模型参数定义写法存在注册失效风险
模型初始化时先将线性层存入普通Python列表,后续才转成nn.Sequential封装。虽然当前写法最终能被识别为模型子模块,但这种方式存在注册顺序的边界问题,如果在参数封装前就初始化优化器,会导致所有可训练参数无法被优化器捕获,出现参数不更新、训练不收敛的问题。 - 损失出现负值的核心诱因
标准nn.BCELoss的合法输入要求为:预测值在(0,1)区间、标签值在[0,1]区间,此时计算出的损失值必然为非负。出现负值损失通常有两类触发原因:- 标签未做二分类归一化,标签值超出[0,1]范围(比如原标签使用1、2映射类别,未转换为0、1格式),代入交叉熵公式后会算出无意义的负损失值
- 训练过程参数更新发散,结合偏大的学习率、未归一化的输入像素值,会导致模型参数更新幅度过大,最终损失完全脱离正常范围
修正方案
- 简化模型结构,删除冗余的ReLU层,替换为直接定义的线性层:
class LogisticRegression(nn.Module): def __init__(self): super(LogisticRegression, self).__init__() # 直接定义线性层为模型直属属性,避免注册失效 self.linear = nn.Linear(in_features=28*28, out_features=1) def forward(self, x): # 保留标准逻辑回归的Sigmoid输出 return torch.sigmoid(self.linear(x))
- 调整训练循环的梯度处理逻辑,将梯度清零操作移到反向传播前,避免复杂计算流图下的梯度累积问题:
# 每个batch的标准流程 optimizer.zero_grad() y_predicted = LR_model(images) total_loss = criterion(y_predicted, labels.unsqueeze(1)) total_loss.backward() optimizer.step()
- 额外检查两个前置条件:
- 输入图像的像素值是否缩放到0-1区间,避免过大的输入值导致参数更新发散
- 标签值是否统一转换为0、1的二分类格式,确保落在BCELoss的合法输入范围内
内容的提问来源于stack exchange,提问作者racycle
相关产品推荐
相关产品推荐

