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

PyTorch技术问询:使用ImageFolder加载数据时如何应用k-fold cross validation?

这问题问得太实用了!很多人手动划分完train/val/test之后,就不知道怎么适配k折交叉验证了,我来给你一步步讲清楚具体操作👇

核心思路先理清楚

首先要划重点:你的独立test/文件夹全程只能用来做最终的模型泛化能力评估,绝对不能掺和到k折的划分流程里。我们需要把原来的train/和val/文件夹合并成一个新的train_pool/文件夹——毕竟k折的核心就是在同一个数据集里反复拆分训练和验证集,原来手动分的val集就没必要单独留着啦。之后就在这个合并后的数据集上做k折,每次用k-1份当训练数据,1份当验证数据。

具体实现步骤

1. 先合并原有训练和验证数据

把train/和val/里按类别分的子文件夹(比如train/cat/、val/cat/)完整复制到新的train_pool/目录下,确保每个类别下的样本都合并到一起。举个例子:把train/cat/里的所有图片和val/cat/里的所有图片都放到train_pool/cat/里,其他类别同理操作。

2. 用PyTorch+Sklearn实现k折划分

PyTorch的ImageFolder本身没有直接支持k折的工具,但我们可以结合Sklearn的KFold来轻松实现,步骤如下:

2.1 加载合并后的数据集

先把train_pool/里的数据用ImageFolder加载进来,预处理和你之前用的保持一致就行:

from torchvision.datasets import ImageFolder
from torch.utils.data import DataLoader, Subset
from sklearn.model_selection import KFold
import torch

# 定义你的数据预处理(和之前训练用的完全一样)
transform = ... # 比如ToTensor()、归一化、数据增强等

# 加载合并后的完整训练池
full_train_dataset = ImageFolder(root='./train_pool', transform=transform)

2.2 初始化k折分割器

设置你想要的折数(比如常用的5折),记得打开shuffle并且固定random_state,这样划分结果是随机且可复现的:

k_folds = 5
kfold = KFold(n_splits=k_folds, shuffle=True, random_state=42)

2.3 遍历每一轮折进行训练+验证

这部分是核心,注意每一轮折都要重新初始化模型,不然上一折的训练参数会干扰这一折的结果:

# 遍历每一个折
for fold, (train_ids, val_ids) in enumerate(kfold.split(full_train_dataset)):
    print(f'=== Fold {fold+1}/{k_folds} ===')
    
    # 根据生成的索引创建训练和验证子集
    train_subset = Subset(full_train_dataset, train_ids)
    val_subset = Subset(full_train_dataset, val_ids)
    
    # 创建DataLoader,训练集shuffle,验证集不用
    train_loader = DataLoader(train_subset, batch_size=32, shuffle=True)
    val_loader = DataLoader(val_subset, batch_size=32, shuffle=False)
    
    # 重新初始化模型、优化器、损失函数!!!
    model = ... # 你的卷积神经网络结构,比如ResNet、自定义CNN
    optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
    criterion = torch.nn.CrossEntropyLoss()
    
    # 你的训练+验证流程(和之前单独训练时的逻辑一致)
    num_epochs = 10
    for epoch in range(num_epochs):
        # 训练阶段
        model.train()
        train_loss = 0.0
        for inputs, labels in train_loader:
            optimizer.zero_grad()
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            train_loss += loss.item() * inputs.size(0)
        
        # 验证阶段
        model.eval()
        val_loss = 0.0
        correct = 0
        total = 0
        with torch.no_grad():
            for inputs, labels in val_loader:
                outputs = model(inputs)
                loss = criterion(outputs, labels)
                val_loss += loss.item() * inputs.size(0)
                _, predicted = torch.max(outputs.data, 1)
                total += labels.size(0)
                correct += (predicted == labels).sum().item()
        
        # 打印每轮的结果
        avg_train_loss = train_loss / len(train_subset)
        avg_val_loss = val_loss / len(val_subset)
        val_acc = 100 * correct / total
        print(f'Epoch {epoch+1}: Train Loss = {avg_train_loss:.4f}, Val Loss = {avg_val_loss:.4f}, Val Acc = {val_acc:.2f}%')
    
    # 每折结束后可以保存模型,或者记录关键指标
    torch.save(model.state_dict(), f'model_fold_{fold+1}.pth')

3. 用独立测试集做最终评估

等所有k折训练完成后,你有两种选择来评估模型:

  • 把所有k个模型都在test/上跑一遍,取平均准确率作为最终结果
  • 挑选验证集表现最好的那个模型,单独在test/上测试

加载测试集并评估的代码示例:

# 加载测试集,预处理和训练时完全一致!
test_dataset = ImageFolder(root='./test', transform=transform)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)

# 比如加载第3折的模型(假设它是表现最好的)
best_model = ... # 初始化你的模型结构
best_model.load_state_dict(torch.load('model_fold_3.pth'))
best_model.eval()

# 测试流程
test_correct = 0
test_total = 0
with torch.no_grad():
    for inputs, labels in test_loader:
        outputs = best_model(inputs)
        _, predicted = torch.max(outputs.data, 1)
        test_total += labels.size(0)
        test_correct += (predicted == labels).sum().item()

test_acc = 100 * test_correct / test_total
print(f'Final Test Accuracy: {test_acc:.2f}%')
几个必须注意的坑
  • 绝对不能碰测试集:测试集是用来检验模型真实泛化能力的,一旦让它参与k折划分,你的评估结果会严重偏乐观,完全失去参考价值。
  • 每折必须重新初始化模型:如果不重新初始化,上一折训练出来的参数会带到下一折,相当于泄露了验证集的信息,导致k折的结果不可靠。
  • 预处理必须完全一致:训练、验证、测试集的预处理操作(包括归一化、数据增强等)必须完全相同,否则模型会出现适配问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 08:44:08