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

Mini-batch梯度下降训练鸢尾花模型精度偏低问题求助

问题分析与代码改进建议

你在鸢尾花数据集上用Mini-batch梯度下降训练模型时,精度卡在75-80%,同时损失和精度计算存在多处错误,以下是具体问题和改进方案:

一、数据加载错误

问题:训练集和测试集使用了同一个完整数据集,没有划分训练/测试子集,导致测试时模型在训练数据上评估,无法反映真实泛化能力。
改进:将数据集划分为训练集和测试集,分别构建DataLoader:

from sklearn.model_selection import train_test_split
import torch.utils.data as data

# 假设dataset是原始鸢尾花数据集
train_data, test_data = train_test_split(dataset, test_size=0.2, random_state=42, stratify=dataset.targets)

batch_size = 10
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True) 
test_loader = DataLoader(test_data, batch_size=batch_size, shuffle=False)  # 测试集无需shuffle

二、训练循环的核心错误

1. 迭代次数与epoch混淆

问题:n_iters = 1000被当作epoch数,但1000个epoch对于鸢尾花数据集来说过多,且日志打印逻辑(epochs+steps)计算epoch编号错误。

2. 损失记录错误

问题:每次epoch只记录最后一个batch的损失,而非整个epoch的平均损失,导致损失曲线失真。

3. 标签格式不匹配CrossEntropyLoss要求

问题:transform_label返回的是形状为(N,1)的二维张量,但CrossEntropyLoss要求输入的标签是形状为(N,)的一维类别索引张量,会导致计算错误。

改进后的训练循环:

# 合理设置epoch数,鸢尾花数据集20-50个epoch足够
n_epochs = 30
LOSS = []

# 统一标签转换函数,放在外部避免重复定义
def transform_label(label_data):
    label_map = {"Iris-setosa": 0, "Iris-versicolor": 1, "Iris-virginica": 2}
    # 返回一维张量
    return torch.tensor([label_map[label] for label in label_data], dtype=torch.long)

for epoch in range(n_epochs):  
    epoch_loss = 0.0
    total_batches = 0
    model.train()  # 切换到训练模式
    for inputs, labels in train_loader:
        optim.zero_grad()  # 先清零梯度,避免累积
        out = model(inputs)
        train_labels = transform_label(labels)
        l = loss(out, train_labels)
        l.backward()
        optim.step()
        
        epoch_loss += l.item()
        total_batches += 1
    
    avg_epoch_loss = epoch_loss / total_batches
    LOSS.append(avg_epoch_loss)
    
    # 每5个epoch打印一次训练状态
    if (epoch + 1) % 5 == 0:
        print(f"epoch: {epoch+1}/{n_epochs}, 平均损失: {avg_epoch_loss:.4f}")

三、精度计算函数的严重错误

问题:

  • number_correct未初始化,会抛出变量未定义错误;
  • sum_acc未累加正确预测数,也没有返回最终精度;
  • transform_label返回二维张量,与预测的一维索引形状不匹配;
  • 使用while循环逐个比较效率低下,可直接用张量操作简化。

改进后的精度计算函数:

def accuracy(model, test_loader):
    model.eval()  # 切换到评估模式,关闭dropout/batchnorm等训练层行为
    total_correct = 0
    total_samples = 0
    
    def transform_label(label_data):
        label_map = {"Iris-setosa": 0, "Iris-versicolor": 1, "Iris-virginica": 2}
        return torch.tensor([label_map[label] for label in label_data], dtype=torch.long)
    
    with torch.no_grad():  # 评估时无需计算梯度,节省内存和时间
        for X_test, test_labels in test_loader:
            test_labels = transform_label(test_labels)
            x_label_pre = model(X_test)
            _, x_label_pre_hat = torch.max(x_label_pre, 1)
            
            # 直接用张量比较求和,高效简洁
            correct = torch.sum(x_label_pre_hat == test_labels).item()
            total_correct += correct
            total_samples += len(X_test)
    
    return total_correct / total_samples  # 返回最终准确率

四、模型与优化器的参数调整

问题:Adam优化器的学习率lr=0.01过大,会导致模型训练不稳定,难以收敛到最优解。
改进:

  • 降低Adam的学习率至0.001;
  • 模型结构对于鸢尾花数据集来说偏复杂,可适当简化(可选),但先修复上述错误后再调整。

调整后的优化器配置:

import torch.nn as nn

lr = 0.001
model = NeuralNetwork()
optim = torch.optim.Adam(model.parameters(), lr=lr)
loss = torch.nn.CrossEntropyLoss()

class NeuralNetwork(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear_stack = nn.Sequential(
         nn.Linear(4, 64),  # 减少隐藏层单元数,简化模型
         nn.ReLU(),
         nn.Linear(64, 3),
         )
    def forward(self, x):
        logits = self.linear_stack(x)
        return logits

关键总结

  1. 必须划分训练/测试集,确保评估的是模型泛化能力;
  2. 标签格式要匹配损失函数要求,CrossEntropyLoss需要一维类别索引;
  3. 训练时记录整个epoch的平均损失,评估时使用torch.no_grad()和模型评估模式;
  4. 调整学习率至合适范围,避免过大导致训练震荡。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 23:45:54