You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyTorch训练Chinese MNIST损失收敛固定值、准确率低如何排查

问题排查方向与解决方案

你观察到的收敛值2.708050刚好是15分类任务下随机猜测的交叉熵基准值(计算式为ln(15)≈2.708),说明模型训练完全没有收敛,预测结果等效于随机输出,问题集中在以下三个核心点:

1. 损失函数与输出、标签格式完全不匹配

这是导致模型无法学习的最核心原因:

  • PyTorch内置的CrossEntropyLoss有严格的输入要求:
    • 模型传入的预测值必须是未经过任何激活函数的原始logits,损失内部会自动完成Softmax计算
    • 标签默认要求传入形状为[batch_size]的类别索引张量(dtype为torch.long),不需要手动转成one-hot格式
  • 现有代码的两处错误:
    • 模型最后一层错误添加了Sigmoid()激活,把输出压缩到0-1区间,直接破坏了交叉熵的计算逻辑,反向传播的梯度完全异常
    • 数据集里手动把标签转成了形状为[batch_size, 15]的one-hot编码,和损失要求的标签格式不匹配
  • 修正方案:
    • 删除模型最后一层的Sigmoid(),最后一层全连接直接输出15维原始logits
    • 数据集类不需要生成one-hot标签,直接存储类别索引即可,__getitem__返回一维的类别标签

2. 测试循环准确率计算逻辑错误

现有测试循环用pred.argmax(1) == y计算正确数,但传入的y是one-hot格式的二维张量,和argmax(1)输出的一维预测索引形状不匹配,比较结果永远为False,所以显示的准确率始终低于10%,这个问题会在标签格式修正后同步解决。

3. 训练逻辑错误导致参数无法累积更新

你在每个epoch的循环内部都重新初始化了损失函数和Adam优化器:

for i in tqdm(range(NUM_EPOCHS)):
    train_loop(train_dl,model_mk_47, CrossEntropyLoss(), Adam(model_mk_47.parameters()) )

Adam优化器会存储每个参数的历史动量状态,每次重新初始化都会清空之前所有的更新记录,等于每个epoch都从零开始更新参数,模型自然无法持续收敛。

  • 修正方案:把损失函数、优化器的初始化移到epoch循环外,全局只初始化一次,同时记得在每个epoch训练完成后调用测试循环:
model_mk_47 = NeuralNetwork().to(device) # 优先用float32训练,比double速度快2-4倍,精度完全足够
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model_mk_47.parameters(), lr=1e-3)
NUM_EPOCHS=10
for i in tqdm(range(NUM_EPOCHS)):
    train_loop(train_dl,model_mk_47, loss_fn, optimizer)
    test_loop(test_dl, model_mk_47, loss_fn)

修正后的可复用核心代码

数据集类

class Custom_dataset(Dataset):
    def __init__(self,filepath,value):
        data = [cv2.imread(fp,-1) for fp in filepath]
        data = [i/np.max(i) for i in data]
        data = torch.tensor(data, dtype=torch.float32)
        data = data.view(-1,1,64,64)
        
        self.data = data
        self.size = len(value)
        assert len(filepath)==len(value), 'length mismatch'
        # 直接存储类别索引,无需one-hot
        self.targets = torch.tensor([value_idx[i] for i in value], dtype=torch.long)
        
        print('data shape ',self.data.shape)
        
    def __getitem__(self,idx):
        return (self.data[idx,:], self.targets[idx])
    
    def __len__(self):
        return self.size

模型结构

class NeuralNetwork(nn.Module):
    def __init__(self):
        super(NeuralNetwork, self).__init__()
        self.flatten = nn.Flatten()
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(64*64, 64*32),
            nn.ReLU(),
            nn.Linear(64*32, 32*32),
            nn.ReLU(),
            nn.Linear(32*32, 16*32),
            nn.ReLU(),
            nn.Linear(32*16, 16*16),
            nn.ReLU(),
            nn.Linear(16*16, 15)
        )

    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits

按以上点修改后,训练损失会快速下降,该数据集上简单MLP的准确率可以轻松达到90%以上。

内容的提问来源于stack exchange,提问作者Akash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 02:48:37