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

PyTorch模型训练精度低于随机猜测,求故障原因

PyTorch模型训练精度远低于随机猜测的问题排查与修复

核心问题分析

  • 训练/测试集完全重叠:你定义的SDSS和testSDSS类加载了同一个SDSS.csv文件,没有划分独立的训练集和测试集,无法真实评估模型的泛化能力。
  • 测试阶段正确数未累加:测试循环中n_correct = (predictions == labels).sum().item()是赋值而非累加,导致最终仅统计最后一个batch的正确样本数,精度计算完全错误。
  • 输入特征未标准化:不同特征的量级可能差异极大,导致模型梯度更新不稳定,难以收敛。
  • 训练步骤数计算错误:n_total_steps = len(dataset)错误使用样本总数作为step数,实际应使用len(data_loader)(即batch的总数)。
  • 数据与模型未绑定设备:代码中未将模型和输入数据移到指定device,后续切换GPU会出现兼容问题。
  • 冗余张量操作:inputs = torch.flatten(inputs)在模型前向传播后执行,对训练无任何作用,属于无效代码。

修复后的完整代码

import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 设备配置
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

input_size = 5
hidden_size = 10
num_classes = 3
num_epochs = 100
batch_size = 10
learning_rate = 0.001  # Adam默认学习率为0.001,适当调大更易收敛

# 统一数据集类,支持传入划分好的特征和标签
class SDSSDataset(Dataset):
    def __init__(self, features, labels):
        self.x_data = torch.from_numpy(features).float()
        self.y_data = torch.from_numpy(labels).long()  # 直接转为long类型,避免后续重复转换
        self.n_samples = features.shape[0]

    def __getitem__(self, index):
        return self.x_data[index], self.y_data[index]

    def __len__(self):
        return self.n_samples

# 数据预处理流程
# 1. 读取原始数据
xy = np.loadtxt('SDSS.csv', delimiter=',', dtype=np.float32, skiprows=0)
labels = xy[:, 0]
features = xy[:, 1:]

# 2. 确保标签从0开始(CrossEntropyLoss要求标签范围为0~num_classes-1)
if np.min(labels) == 1:
    labels = labels - 1

# 3. 划分训练/测试集(8:2比例,分层抽样保证类别分布一致)
train_features, test_features, train_labels, test_labels = train_test_split(
    features, labels, test_size=0.2, random_state=42, stratify=labels
)

# 4. 特征标准化(关键步骤,消除特征量级差异)
scaler = StandardScaler()
train_features = scaler.fit_transform(train_features)
test_features = scaler.transform(test_features)

# 创建数据加载器
train_dataset = SDSSDataset(train_features, train_labels)
test_dataset = SDSSDataset(test_features, test_labels)

train_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=learning_rate)

# 训练循环
n_total_steps = len(train_loader)  # 正确的step数为batch总数
for epoch in range(num_epochs):
    print(f'epoch: {epoch + 1} / {num_epochs}')
    
    model.train()
    for i, (inputs, labels) in enumerate(train_loader):
        # 将数据移到指定设备
        inputs = inputs.to(device)
        labels = labels.to(device)
        
        # 前向传播
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        
        # 反向传播与参数更新
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        if (i + 1) % 100 == 0:
            print(f'epoch {epoch + 1}/{num_epochs}, step {i + 1}/{n_total_steps}, loss = {loss.item():.4f}')

# 测试模型
model.eval()  # 切换到评估模式,关闭Dropout等训练特有的层
with torch.no_grad():
    n_correct = 0
    n_samples = 0
    for inputs, labels in test_loader:
        inputs = inputs.to(device)
        labels = labels.to(device)
        
        outputs = model(inputs)
        _, predictions = torch.max(outputs, 1)
        
        n_samples += labels.shape[0]
        n_correct += (predictions == labels).sum().item()  # 累加正确样本数
    
    acc = 100 * n_correct / n_samples
    print(f'测试集准确率 = {acc:.2f}%')

额外优化建议

  • 类别不平衡处理:如果数据集存在类别占比差异大的情况,可使用加权CrossEntropyLoss或过采样/欠采样策略。
  • 模型复杂度调整:当前模型较简单,可尝试增加隐藏层数量、神经元个数,或添加Dropout层防止过拟合。
  • 学习率调度:使用torch.optim.lr_scheduler.StepLR等学习率衰减策略,在训练后期降低学习率以稳定收敛。
  • 数据增强:若特征允许,可添加适当的扰动操作提升模型泛化能力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 00:16:07