Keras是否内置方法将未拆分数据集划分为训练、验证、测试集?
Keras拆分未预先划分的类别式数据集
当然有啦!Keras针对这种按类别子文件夹存放的未拆分数据集,提供了非常实用的工具,完全不用你手动写复杂的拆分脚本。下面给你分享两种最常用的方法:
方法一:使用image_dataset_from_directory(推荐,TensorFlow 2.3+适用)
这个API是TensorFlow 2.3之后推出的,能直接从类别子文件夹加载数据,同时一键完成训练集、验证集的拆分,甚至可以间接得到测试集,用法特别简洁。
先看你的数据集结构:
data/ ├── cats/ │ ├── cat1.jpg │ ├── cat2.jpg │ └── ... └── dogs/ ├── dog1.jpg ├── dog2.jpg └── ...
拆分训练集+验证集
直接用以下代码就能搞定:
import tensorflow as tf from tensorflow.keras.utils import image_dataset_from_directory # 加载训练集 train_ds = image_dataset_from_directory( 'data/', validation_split=0.2, # 预留20%的数据作为验证集 subset="training", seed=123, # 固定随机种子,保证每次拆分结果一致 image_size=(150, 150), # 统一图片尺寸,适配模型输入 batch_size=32 ) # 加载验证集 val_ds = image_dataset_from_directory( 'data/', validation_split=0.2, subset="validation", seed=123, # 和训练集用同一个seed,确保拆分不重叠 image_size=(150, 150), batch_size=32 )
额外拆分测试集
如果还需要单独的测试集,可以分两步走:先拆分出「训练+验证池」和测试集,再从池子里拆分训练集和验证集:
# 第一步:拆分出训练验证池(80%)和测试集(20%) train_val_ds = image_dataset_from_directory( 'data/', validation_split=0.2, subset="training", seed=456, image_size=(150, 150), batch_size=32 ) test_ds = image_dataset_from_directory( 'data/', validation_split=0.2, subset="validation", seed=456, image_size=(150, 150), batch_size=32 ) # 第二步:从训练验证池中拆分90%作为训练集,10%作为验证集 # 这样总数据比例就是72%训练、8%验证、20%测试 train_ds = train_val_ds.take(int(len(train_val_ds)*0.9)) val_ds = train_val_ds.skip(int(len(train_val_ds)*0.9))
方法二:ImageDataGenerator配合train_test_split(旧版兼容方案)
如果你习惯用ImageDataGenerator做数据增强,也可以结合scikit-learn的train_test_split手动拆分文件路径,再用生成器加载数据。
步骤示例代码:
import os import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from tensorflow.keras.preprocessing.image import ImageDataGenerator # 第一步:收集所有图片的路径和对应标签 data_dir = 'data/' classes = ['cats', 'dogs'] file_paths = [] labels = [] for cls_idx, cls_name in enumerate(classes): cls_dir = os.path.join(data_dir, cls_name) for img_name in os.listdir(cls_dir): file_paths.append(os.path.join(cls_dir, img_name)) labels.append(cls_idx) # 第二步:拆分训练验证池和测试集(8:2) # 注意*stratify=labels*参数,保证每个类别的比例在拆分后和原数据集一致 train_val_paths, test_paths, train_val_labels, test_labels = train_test_split( file_paths, labels, test_size=0.2, random_state=123, stratify=labels ) # 第三步:拆分训练集和验证集(9:1) train_paths, val_paths, train_labels, val_labels = train_test_split( train_val_paths, train_val_labels, test_size=0.1, random_state=456, stratify=train_val_labels ) # 第四步:用数据生成器加载数据 datagen = ImageDataGenerator(rescale=1./255) # 归一化像素值 train_ds = datagen.flow_from_dataframe( dataframe=pd.DataFrame({'path': train_paths, 'label': train_labels}), x_col='path', y_col='label', target_size=(150,150), batch_size=32, class_mode='binary' ) val_ds = datagen.flow_from_dataframe( dataframe=pd.DataFrame({'path': val_paths, 'label': val_labels}), x_col='path', y_col='label', target_size=(150,150), batch_size=32, class_mode='binary' ) test_ds = datagen.flow_from_dataframe( dataframe=pd.DataFrame({'path': test_paths, 'label': test_labels}), x_col='path', y_col='label', target_size=(150,150), batch_size=32, class_mode='binary', shuffle=False # 测试集不需要打乱,方便后续评估 )
关键注意点
- 无论用哪种方法,都要记得用随机种子(比如
seed或random_state)固定拆分结果,这样实验才能复现 - 拆分时一定要保证类别比例一致:方法一中
image_dataset_from_directory会自动分层,方法二中要加上stratify参数,避免某类别在某个子集里占比过高,保证模型训练的公平性
内容的提问来源于stack exchange,提问作者Oblomov
相关产品推荐
相关产品推荐

