PyTorch模型训练不收敛?精度计算错误排查与修正

php中文网
发布: 2025-12-03 08:42:13
原创
620人浏览过

PyTorch模型训练不收敛?精度计算错误排查与修正

本文针对pytorch模型训练中出现的精度不提升、甚至低于随机猜测的问题进行深入探讨。核心原因在于模型评估阶段对正确预测数量的累积方式不当,以及输入数据维度处理和标签维度的潜在错误。教程将详细分析这些常见错误,并提供正确的代码实现,帮助开发者有效诊断并解决模型训练效果不佳的困境,确保模型评估的准确性。

引言:模型训练精度不佳的困扰

深度学习模型开发过程中,开发者常常会遇到模型训练效果不理想,甚至在经过数百个Epoch后,其在测试集上的表现仍然不如随机猜测的情况。面对这种问题,许多人会首先尝试调整批量大小、网络层数、学习率或Epoch数量等超参数,但往往徒劳无功。这不仅令人沮丧,也阻碍了模型的进一步优化。实际上,有时问题的根源并非出在模型架构或训练算法本身,而在于数据处理流程、维度匹配或最常见的——模型性能评估逻辑中的细微错误。

原始代码分析与潜在问题诊断

为了更好地理解并解决这类问题,我们将对提供的PyTorch代码进行逐一分析,并指出其中可能导致模型精度异常的关键点。

1. 数据加载与预处理

代码中定义了SDSS和testSDSS两个几乎完全相同的数据集类,都从SDSS.csv文件中加载数据。

  • 重复定义: 这种重复定义是不必要的。通常,一个Dataset类足以,然后通过torch.utils.data.random_split或手动加载不同文件来创建训练集和测试集。
  • 数据维度:
    • self.x_data = torch.from_numpy(xy[:, 1:]):特征数据,形状为 [n_samples, n_features] (例如 [N, 5])。
    • self.y_data = torch.from_numpy(xy[:, [0]]):标签数据,形状为 [n_samples, 1] (例如 [N, 1])。这种形状对于分类任务的CrossEntropyLoss而言,通常需要进一步处理为 [n_samples]。

2. 模型架构

NeuralNet是一个简单的两层全连接网络,中间使用LeakyReLU激活函数,输出层直接连接到num_classes,没有显式的softmax,这与nn.CrossEntropyLoss的内部实现是兼容的。

3. 训练循环中的关键问题

训练循环遵循了PyTorch的标准模式:前向传播、损失计算、反向传播、优化器更新。然而,其中存在几个关键的维度处理问题:

  • 问题A:输入数据维度处理错误 inputs = torch.flatten(inputs) 在训练循环的每次迭代中,都执行了 inputs = torch.flatten(inputs)。

    • 解析: DataLoader通常会输出形状为 [batch_size, input_size] 的批次数据。如果 input_size 为5,那么 inputs 的形状是 [batch_size, 5]。对其执行 torch.flatten(inputs) 会将其转换为 [batch_size * 5]。然而,模型中的第一个线性层 self.l1 = nn.Linear(input_size, hidden_size) 期望的输入是 [batch_size, input_size]。这种维度不匹配会导致模型在接收数据时出现问题,或者更隐蔽地,模型会尝试将 [batch_size * 5] 解释为 [batch_size, 5],从而导致训练失败或模型无法学习。正确做法是移除这行代码。
  • 问题B:标签数据维度处理 labels = torch.flatten(labels) 在训练循环中,标签也被 flatten 处理。

    • 解析: nn.CrossEntropyLoss 期望分类任务的标签是形状为 [batch_size] 的1D张量,其中包含类别索引(0到num_classes-1)。由于原始标签 self.y_data 是 [n_samples, 1],经过 DataLoader 批处理后为 [batch_size, 1]。对其执行 flatten 确实可以将其转换为 [batch_size]。但是,更语义化且更推荐的做法是使用 labels.squeeze(1) 来移除单维度。
  • 问题C:训练步数统计 n_total_steps = len(dataset) 在训练循环外,n_total_steps 被设置为 len(dataset),即总样本数。

    • 解析: 在 print 语句中,step {i+1}/{n_total_steps} 中的 n_total_steps 应该表示批次的总数量,而非样本总数。正确的应该是 len(data_loader)。

4. 评估循环:精度计算的核心错误

这是导致模型精度“低于随机猜测”的最主要原因。

音刻
音刻

AI音视频转录和笔记工具

音刻 107
查看详情 音刻
  • 错误代码:

    # ...
    n_correct = 0
    n_samples = 0
    for inputs, labels in test_loader:
        # ...
        _, predictions = torch.max(outputs, 1)
        n_samples += labels.shape[0]
        n_correct = (predictions == labels).sum().item() # 核心错误所在!
    
    acc = 100 * n_correct / n_samples
    print(f'accuracy = {acc}')
    登录后复制
  • 问题解析: 在 for 循环中,每次迭代处理一个批次时,n_correct = (predictions == labels).sum().item() 这行代码都会重新赋值 n_correct。这意味着 n_correct 变量在每次批次处理后都会被当前批次的正确预测数覆盖,而不是将所有批次的正确预测数累加起来。最终,当循环结束时,n_correct 将只包含最后一个批次的正确预测数量。因此,计算出的 acc 值将是极低的,完全无法反映模型在整个测试集上的真实性能。

解决方案与代码修正

针对上述诊断出的问题,我们将进行以下修正:

  1. 修正精度累积: 将评估循环中的 n_correct = ... 改为 n_correct += ...。
  2. 修正输入维度: 移除训练和评估循环中对 inputs 的 flatten 操作。
  3. 修正标签维度: 将训练和评估循环中对 labels 的 flatten 操作改为 labels.squeeze(1)。
  4. 修正训练步数统计: 将 n_total_steps 的计算方式改为 len(data_loader)。
  5. 优化数据集类: 建议合并SDSS和testSDSS,并使用random_split进行数据集划分。

以下是修正后的关键代码片段:

import torch
import torch.nn as nn
import numpy as np
from torch.utils.data import Dataset, DataLoader
import torch.optim

# 设备配置
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 优先使用GPU

# 超参数
input_size = 5
hidden_size = 10
num_classes = 3
num_epochs = 100
batch_size = 10
learning_rate = 0.0001

# 修正后的Dataset类,支持训练/测试划分
class SDSSDataset(Dataset):
    def __init__(self, filepath='SDSS.csv'):
        xy = np.loadtxt(filepath, delimiter=',', dtype=np.float32, skiprows=0)
        self.n_samples = xy.shape[0]
        self.x_data = torch.from_numpy(xy[:, 1:]) # 特征
        self.y_data = torch.from_numpy(xy[:, [0]]) # 标签,形状 [n_samples, 1]

    def __getitem__(self, index):
        # 返回特征和标签,标签在这里不做squeeze,留给DataLoader之后处理
        return self.x_data[index], self.y_data[index]

    def __len__(self):
        return self.n_samples

# 加载数据集并进行训练/测试集划分
full_dataset = SDSSDataset()
train_size = int(0.8 * len(full_dataset)) # 80% 用于训练
test_size = len(full_dataset) - train_size # 20% 用于测试
train_dataset, test_dataset = torch.utils.data.random_split(full_dataset, [train_size, test_size])

data_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True, num_workers=0)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False, num_workers=0)

# 模型定义 (不变)
class NeuralNet(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super(NeuralNet,self).__init__()
        self.l1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.LeakyReLU()
        self.l2 = nn.Linear(hidden_size, num_classes)

    def forward(self, x):
        out = self.l1(x)
        out = self.relu(out)
        out = self.l2(out)
        return out

model = NeuralNet(input_size, hidden_size, num_classes).to(device) # 将模型移到设备

# 损失函数和优化器 (不变)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr
登录后复制

以上就是PyTorch模型训练不收敛?精度计算错误排查与修正的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号