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

CNN模型训练与验证准确率提升过慢问题咨询(Olivetti数据集)

问题分析与解决方案

嘿,我来帮你梳理下这个问题!首先明确说:前500轮准确率几乎没提升绝对不正常,咱们从代码里找几个关键问题,一步步解决:

1. 最核心的问题:训练方式错误(全批量+无数据打乱)

你现在的训练逻辑是每次循环都把整个训练集一次性喂给模型,而且全程没有打乱数据。这种全批量梯度下降(Full-Batch GD)在小数据集上收敛极慢——梯度更新频率太低,且没有数据噪音帮助模型跳出局部最优。

另外,你定义了train_loader但完全没用到它,等于白做了分批处理的准备。

2. 优化器配置不合理

你用的是纯SGD,没有加momentum,学习率0.03在全批量场景下要么太大导致震荡,要么太小导致模型“不动”。SGD+Momentum能显著加速收敛,尤其是在损失平坦的区域。

3. 其他细节问题

  • 没有切换训练/验证模式:训练时应该用model.train(),验证时用model.eval()(虽然你的模型没有BatchNorm/Dropout,但养成好习惯很重要)。
  • 验证时没关闭梯度计算:用torch.no_grad()包裹验证代码,能大幅节省内存和计算时间。

修改后的代码示例

我把你的代码做了关键调整,你可以直接运行试试:

# -*- coding: utf-8 -*- 
#Libraries 
import torch 
import torch.nn.functional as F 
from torch import nn 
import numpy as np 
import matplotlib.pyplot as plt 
from torch.utils.data import TensorDataset, DataLoader 
from sklearn.datasets import fetch_olivetti_faces 
from sklearn.model_selection import train_test_split # 用sklearn划分数据集更简洁

# Olivetti dataset download 
olivetti = fetch_olivetti_faces() 
X = olivetti.images 
Y = olivetti.target 
print("\nDownload Ok") 

# 分层划分数据集,保证每个类的训练/验证比例一致
X_train, X_val, Y_train, Y_val = train_test_split(X, Y, test_size=0.2, stratify=Y, random_state=42)

# 调整形状并转成Tensor:(样本数, 通道数, 高, 宽)
X_train = torch.Tensor(X_train).unsqueeze(1) # 增加通道维度,变成(320,1,64,64)
Y_train = torch.LongTensor(Y_train)
X_val = torch.Tensor(X_val).unsqueeze(1)
Y_val = torch.LongTensor(Y_val)

# 绑定数据与标签,用DataLoader分批处理
batch_size = 16
train_dataset = TensorDataset(X_train, Y_train)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) # 训练时强制打乱
val_dataset = TensorDataset(X_val, Y_val)
val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)

class CNNModule(nn.Module): 
    def __init__(self): 
        super(CNNModule, self).__init__() 
        self.conv1 = nn.Conv2d(1, 6, 5) 
        self.pool = nn.MaxPool2d(2, 2) 
        self.conv2 = nn.Conv2d(6, 16, 5) 
        self.fc1 = nn.Linear(16 * 13 * 13, 120) 
        self.fc2 = nn.Linear(120, 84) 
        self.fc3 = nn.Linear(84, 40) 
    def forward(self, x): 
        x = self.pool(F.relu(self.conv1(x))) 
        x = self.pool(F.relu(self.conv2(x))) 
        x = x.view(-1, 16 * 13 * 13) 
        x = F.relu(self.fc1(x)) 
        x = F.relu(self.fc2(x)) 
        x = self.fc3(x) 
        return x 

def make_train(model, train_loader, val_loader, n_epochs, gpu): 
    criterion = nn.CrossEntropyLoss() 
    # 改用SGD+Momentum,收敛速度会快很多;也可以试试Adam优化器(注释里有写)
    optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9) 
    # optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

    # 记录训练过程
    train_losses = []
    train_accs = []
    val_losses = []
    val_accs = []

    # GPU配置
    device = torch.device("cuda" if gpu and torch.cuda.is_available() else "cpu")
    model.to(device)
    print(f"Using {device}")

    for epoch in range(n_epochs):
        # 训练阶段
        model.train()
        train_loss = 0.0
        train_correct = 0
        total_train = 0
        for batch_x, batch_y in train_loader:
            batch_x, batch_y = batch_x.to(device), batch_y.to(device)
            
            optimizer.zero_grad() # 先清零梯度,避免累积
            outputs = model(batch_x)
            loss = criterion(outputs, batch_y)
            loss.backward()
            optimizer.step()

            # 累计损失与准确率
            train_loss += loss.item() * batch_x.size(0)
            _, predicted = torch.max(outputs.data, 1)
            total_train += batch_y.size(0)
            train_correct += (predicted == batch_y).sum().item()
        
        avg_train_loss = train_loss / total_train
        avg_train_acc = train_correct / total_train
        train_losses.append(avg_train_loss)
        train_accs.append(avg_train_acc)

        # 验证阶段
        model.eval()
        val_loss = 0.0
        val_correct = 0
        total_val = 0
        with torch.no_grad(): # 关闭梯度计算,节省资源
            for batch_x, batch_y in val_loader:
                batch_x, batch_y = batch_x.to(device), batch_y.to(device)
                outputs = model(batch_x)
                loss = criterion(outputs, batch_y)

                val_loss += loss.item() * batch_x.size(0)
                _, predicted = torch.max(outputs.data, 1)
                total_val += batch_y.size(0)
                val_correct += (predicted == batch_y).sum().item()
        
        avg_val_loss = val_loss / total_val
        avg_val_acc = val_correct / total_val
        val_losses.append(avg_val_loss)
        val_accs.append(avg_val_acc)

        # 每5个epoch打印一次结果
        if (epoch + 1) % 5 == 0:
            print(f"Epoch --> {epoch+1}")
            print(f"Train Loss : {avg_train_loss:.4f}, Train Accuracy : {avg_train_acc:.4f}")
            print(f"Validation Loss : {avg_val_loss:.4f}, Validation Accuracy : {avg_val_acc:.4f}\n")

    # 绘制训练曲线
    plt.figure(figsize=(12,8))
    plt.subplot(2,2,1)
    plt.plot(np.arange(n_epochs), train_losses, 'r-', label='Train Loss')
    plt.legend()
    plt.title('Train Loss')
    plt.subplot(2,2,2)
    plt.plot(np.arange(n_epochs), train_accs, 'b--', label='Train Accuracy')
    plt.legend()
    plt.title('Train Accuracy')
    plt.subplot(2,2,3)
    plt.plot(np.arange(n_epochs), val_losses, 'r-', label='Val Loss')
    plt.legend()
    plt.title('Validation Loss')
    plt.subplot(2,2,4)
    plt.plot(np.arange(n_epochs), val_accs, 'b--', label='Val Accuracy')
    plt.legend()
    plt.title('Validation Accuracy')
    plt.show()

# 初始化模型并开始训练
gpu = True
model = CNNModule()
make_train(model, train_loader, val_loader, n_epochs=50, gpu=gpu)

关键修改点说明

  1. 分批训练+数据打乱:用TensorDataset绑定数据和标签,DataLoader设置shuffle=True,每次用小批量数据训练,梯度更新更频繁,数据噪音也能帮助模型更快跳出局部最优。
  2. 优化器升级:添加momentum=0.9让SGD“带惯性”,或者直接用Adam优化器(对学习率容忍度更高,收敛速度更快)。
  3. 规范训练流程:加入model.train()和model.eval()切换模式,用torch.no_grad()关闭验证阶段的梯度计算,避免不必要的资源消耗。
  4. 合理划分数据集:用sklearn的分层划分,保证每个类的训练/验证样本比例一致,避免数据分布不均影响模型收敛。

预期效果

修改后,你应该能看到训练准确率在前10个epoch左右就开始明显提升,不会再出现前几百轮几乎不动的情况。如果还是收敛慢,可以试试微调学习率(SGD建议0.005-0.01,Adam建议0.001-0.0001),或者给模型添加BatchNorm层稳定训练过程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 18:52:32