别再只用ImageNet格式了!用Python脚本一键生成Vim模型训练所需的分类数据集
·
用Python脚本重构图像分类数据集:从杂乱文件夹到Vim模型标准输入的完整指南
当你面对一堆按类别存放却杂乱无章的图像数据时,是否曾为手动整理成模型可读格式而头疼?本文将彻底解决这个痛点,带你用Python脚本实现从原始数据到Vim模型标准输入的自动化转换。
1. 为什么需要重构数据集结构
大多数深度学习框架默认采用ImageNet标准目录结构,即 train/val 分目录下按类别存放的层级格式。但现实中我们收集的原始数据往往呈现以下两种典型状态:
- 类别文件夹混杂 :所有类别文件夹平铺在根目录下,无训练/验证划分
- 文件命名混乱 :不同来源的图片存在命名冲突或格式不统一
手动整理这类数据不仅耗时,还容易引入人为错误。我们开发的 makedata.py 脚本能实现以下核心功能:
# 主要功能概览
1. 自动划分训练集/验证集(可调比例)
2. 保持类别目录结构的同时重组文件路径
3. 处理文件名冲突并保留原始图像
4. 生成标准ImageNet格式的目录树
2. 环境准备与依赖安装
2.1 基础环境配置
推荐使用Python 3.8+环境,主要依赖库包括:
| 库名称 | 版本要求 | 功能说明 |
|---|---|---|
| scikit-learn | ≥1.0 | 数据集划分 |
| Pillow | ≥9.0 | 图像处理 |
| opencv-python | ≥4.5 | 图像格式转换 |
| tqdm | - | 进度显示 |
安装命令:
pip install scikit-learn pillow opencv-python tqdm
2.2 目录结构检测
脚本会先检查输入目录的合法性,确保结构符合预期:
def validate_structure(root_dir):
"""验证原始数据目录结构"""
if not os.path.exists(root_dir):
raise ValueError(f"目录不存在: {root_dir}")
classes = [d for d in os.listdir(root_dir)
if os.path.isdir(os.path.join(root_dir, d))]
if not classes:
raise ValueError("未找到任何类别子目录")
return sorted(classes)
3. 核心脚本实现详解
3.1 数据集智能划分
采用分层抽样保证各类别分布均衡:
from sklearn.model_selection import train_test_split
def split_dataset(image_paths, test_size=0.2, seed=42):
"""保持类别比例划分数据集"""
# 按类别分组
class_groups = {}
for path in image_paths:
class_name = path.split(os.sep)[-2]
class_groups.setdefault(class_name, []).append(path)
# 分层划分
train_files, val_files = [], []
for cls, files in class_groups.items():
cls_train, cls_val = train_test_split(
files, test_size=test_size, random_state=seed)
train_files.extend(cls_train)
val_files.extend(cls_val)
return train_files, val_files
提示:设置
random_state参数可确保每次划分结果一致
3.2 文件操作优化技巧
处理大规模数据时需注意:
- 内存优化 :使用生成器而非列表存储路径
- 进度可视化 :整合tqdm进度条
- 错误处理 :跳过损坏图像文件
def copy_files(file_list, target_dir, desc=""):
"""带进度显示的安全文件拷贝"""
os.makedirs(target_dir, exist_ok=True)
for src_path in tqdm(file_list, desc=desc):
try:
class_name = os.path.basename(os.path.dirname(src_path))
dst_dir = os.path.join(target_dir, class_name)
os.makedirs(dst_dir, exist_ok=True)
shutil.copy2(src_path,
os.path.join(dst_dir, os.path.basename(src_path)))
except Exception as e:
print(f"Error copying {src_path}: {str(e)}")
4. 进阶功能扩展
4.1 数据增强预处理
在复制文件时直接应用基础增强:
from torchvision import transforms
basic_aug = transforms.Compose([
transforms.Resize(256),
transforms.RandomCrop(224),
transforms.RandomHorizontalFlip(),
])
def apply_augmentation(src_path, dst_path):
img = Image.open(src_path)
img = basic_aug(img)
img.save(dst_path)
4.2 元数据生成
自动生成数据集统计信息:
def generate_metadata(dataset_dir):
stats = {
"total_images": 0,
"class_distribution": {},
"split_counts": {}
}
for split in ["train", "val"]:
split_dir = os.path.join(dataset_dir, split)
if not os.path.exists(split_dir):
continue
stats["split_counts"][split] = 0
for class_name in os.listdir(split_dir):
class_dir = os.path.join(split_dir, class_name)
count = len(os.listdir(class_dir))
stats["class_distribution"].setdefault(class_name, {})
stats["class_distribution"][class_name][split] = count
stats["split_counts"][split] += count
stats["total_images"] += count
return stats
5. 完整脚本集成
最终整合的 makedata.py 包含以下功能模块:
-
命令行参数解析
import argparse parser = argparse.ArgumentParser() parser.add_argument("--src_dir", required=True, help="原始数据目录") parser.add_argument("--dst_dir", default="dataset", help="输出目录") parser.add_argument("--test_ratio", type=float, default=0.2) parser.add_argument("--seed", type=int, default=42) args = parser.parse_args() -
主流程控制
def main(): # 1. 验证输入结构 classes = validate_structure(args.src_dir) # 2. 收集所有图像路径 image_paths = [] for cls in classes: cls_dir = os.path.join(args.src_dir, cls) image_paths.extend([ os.path.join(cls_dir, f) for f in os.listdir(cls_dir) if f.lower().endswith(('.png', '.jpg', '.jpeg')) ]) # 3. 划分数据集 train_files, val_files = split_dataset(image_paths, args.test_ratio, args.seed) # 4. 拷贝文件 copy_files(train_files, os.path.join(args.dst_dir, "train"), "创建训练集") copy_files(val_files, os.path.join(args.dst_dir, "val"), "创建验证集") # 5. 生成统计信息 stats = generate_metadata(args.dst_dir) print(f"数据集创建完成,统计信息:{stats}") -
异常处理框架
if __name__ == "__main__": try: main() except Exception as e: print(f"程序执行出错: {str(e)}") sys.exit(1)
6. 与Vim模型训练流程对接
生成的标准结构可直接用于Vim模型训练:
from torchvision.datasets import ImageFolder
train_dataset = ImageFolder(
root="dataset/train",
transform=your_transforms
)
val_dataset = ImageFolder(
root="dataset/val",
transform=your_transforms
)
典型训练循环示例:
def train_epoch(model, loader, criterion, optimizer):
model.train()
total_loss = 0
for inputs, targets in loader:
inputs = inputs.to(device)
targets = targets.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, targets)
loss.backward()
optimizer.step()
total_loss += loss.item()
return total_loss / len(loader)
7. 实际应用中的经验技巧
在处理植物幼苗分类项目时,我们发现几个关键点:
- 小样本类别处理 :当某些类别样本少于50张时,采用过采样策略
- 文件名规范化 :统一转换为小写并替换空格为下划线
- 缓存机制 :对已处理的数据集添加标记文件避免重复处理
# 示例:处理文件名特殊字符
def sanitize_filename(filename):
filename = filename.lower()
filename = re.sub(r'[^\w.-]', '_', filename)
return filename[:128] # 限制最大长度
通过这个自动化流程,我们成功将数据准备时间从原来的数小时缩短到几分钟,且完全避免了人工操作可能引入的错误。
更多推荐
所有评论(0)