PyTorch中无独立训练/测试目录时,基于ImageFolder划分训练、验证、测试集的方法是否可行?
问题解答与代码优化
首先回应你的核心疑问:只要划分过程保证了训练/验证/测试集的完全独立,且三个集合的类别分布与原数据集一致,这样的划分是符合标准验证/测试集定义的。不过你的代码目前存在两个关键问题,会影响划分的合理性,下面详细说明:
一、核心疑问的解答
标准的验证集(开发集)作用是:在训练过程中评估模型性能、调整超参数(比如学习率、batch size等);测试集则是完全独立于训练流程的,仅在模型最终训练完成后用来评估泛化能力,全程不能参与任何调参或训练环节。
你的划分思路(先拆分训练/验证,再将验证拆分为验证/测试)本身是可行的,但需要满足两个核心前提:
- 三个数据集完全无重叠:不能出现同一个样本同时出现在两个集合里的情况
- 分层划分:保证每个类别的样本在三个集合中的占比和原数据集一致,避免某类别在测试集中缺失或占比失衡的情况
二、你的代码存在的问题
1. 验证集与测试集数据重叠
看你代码中的这部分:
# Creating a valid and test set valid_idx = valid_idx[int(np.floor(0.2*len(valid_idx))) : len(valid_idx)] test_idx = valid_idx[0:int(np.floor (0.2 * len(valid_idx) ) )]
这段代码的逻辑是:先把原valid_idx的后80%重新赋值给valid_idx,然后从**新的valid_idx**中取前20%作为test_idx——这会导致test_idx的样本完全包含在新的valid_idx里,两个集合出现严重重叠!这是绝对不能出现的,因为验证集和测试集必须完全独立。
2. 未做分层随机划分
你当前只是对所有样本的索引做了随机打乱,然后直接按比例拆分,没有考虑样本的类别标签。如果原数据集的类别分布不均匀(比如某个类别的样本数量特别少),这种随机拆分可能导致某个类别在测试集中没有样本,或者占比和原数据集差异极大,最终影响模型评估的准确性。
三、优化后的代码方案
推荐使用sklearn的train_test_split来做分层划分,它可以基于类别标签保证每个集合的类别分布和原数据集一致。以下是修正后的代码:
import numpy as np from torchvision import datasets from torch.utils.data import SubsetRandomSampler, DataLoader from sklearn.model_selection import train_test_split # 加载数据集 data = datasets.ImageFolder('PATH', transform=transform) targets = data.targets # 获取每个样本的类别标签 # 第一步:先拆分训练集和临时集(后续拆分为验证+测试) train_idx, temp_idx = train_test_split( np.arange(len(data)), test_size=valid_size, # 这里的valid_size是你原来定义的验证+测试集的总比例 stratify=targets, # 按类别分层划分 random_state=42 # 设置随机种子保证结果可复现 ) # 第二步:把临时集拆分为验证集和测试集 valid_idx, test_idx = train_test_split( temp_idx, test_size=0.2, # 从临时集中取20%作为测试集,剩下80%作为验证集 stratify=[targets[i] for i in temp_idx], # 同样按类别分层 random_state=42 ) # 定义采样器 train_sampler = SubsetRandomSampler(train_idx) valid_sampler = SubsetRandomSampler(valid_idx) test_sampler = SubsetRandomSampler(test_idx) # 构建DataLoader train_loader = DataLoader(data, batch_size=batch_size, sampler=train_sampler, num_workers=num_workers) valid_loader = DataLoader(data, batch_size=batch_size, sampler=valid_sampler, num_workers=num_workers) test_loader = DataLoader(data, batch_size=batch_size, sampler=test_sampler, num_workers=num_workers)
补充说明
- 设置
random_state可以让你的划分结果固定,方便后续复现实验结果 - 分层划分的核心是保证三个数据集的类别分布一致,这对于小数据集或者类别不平衡的数据集尤为重要
- 测试集一定要严格独立,训练过程中绝对不能使用测试集的任何数据(包括查看测试集的性能),否则会导致最终的模型泛化能力评估不准确
内容的提问来源于stack exchange,提问作者Bakhtawar




