YOLOv8数据集标签统计脚本:一键分析训练集/验证集/测试集各类别数量(附完整Python代码)
YOLOv8数据集标签统计与可视化分析实战指南从数据洞察到模型优化YOLOv8标签统计的核心价值在计算机视觉项目中数据质量往往比模型架构更能决定最终效果。对于使用YOLOv8进行目标检测的开发者而言全面掌握数据集的类别分布情况是项目成功的第一步。想象一下当你花费数周时间训练模型后才发现某些关键类别样本不足导致识别率低下——这种问题完全可以通过前期简单的标签统计分析来避免。标签统计不仅仅是数字的堆砌它能揭示数据集的多个关键特征类别平衡性是否存在某些类别样本过少长尾分布数据划分合理性训练集/验证集/测试集的分布是否一致标注质量是否存在异常标注如极端尺寸的边界框本文将提供一个完整的Python解决方案不仅能统计基础标签数量还会通过可视化分析帮助您真正理解数据并基于统计结果给出实用的数据增强建议。这套工具特别适合以下场景使用接手新数据集时的初步质量检查训练前的数据平衡性评估模型表现不佳时的根因分析学术研究中需要报告数据集统计信息数据集结构与统计原理深度解析YOLOv8标注格式的标准化要求规范的YOLOv8数据集应遵循严格的目录结构这是保证统计脚本准确运行的前提。典型结构如下dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/每个.txt标注文件对应同名图像内容格式为class_id x_center y_center width height例如0 0.435 0.512 0.12 0.2 1 0.723 0.341 0.25 0.3注意坐标值均为归一化后的相对值0-1范围这是YOLO格式的核心特征统计脚本的核心算法设计我们的统计脚本将实现以下关键功能递归遍历labels目录下的所有子目录逐文件解析每个.txt文件中的标注信息分类累计不同子集train/val/test的类别出现次数结果可视化生成直观的分布图表算法时间复杂度为O(n)其中n为标注文件总数确保即使处理大规模数据集也能快速完成。完整统计工具实现与代码解读基础统计功能实现以下代码提供了完整的标签统计功能包含详细的类型注解和错误处理from pathlib import Path from collections import defaultdict import matplotlib.pyplot as plt def analyze_yolo_labels(label_root: str) - dict: 统计YOLOv8格式数据集的标签分布 参数: label_root: labels目录的路径 返回: 包含各子集类别统计的嵌套字典 label_path Path(label_root) if not label_path.exists(): raise FileNotFoundError(f标签目录不存在: {label_path}) results { train: defaultdict(int), val: defaultdict(int), test: defaultdict(int), total: defaultdict(int) } for subset in [train, val, test]: subset_dir label_path / subset if not subset_dir.exists(): continue for label_file in subset_dir.glob(*.txt): with open(label_file, r) as f: for line in f: line line.strip() if not line: continue class_id line.split()[0] results[subset][class_id] 1 results[total][class_id] 1 return results统计结果可视化增强纯数字统计不够直观我们添加可视化功能def plot_label_distribution(stats: dict, class_names: list None): 绘制标签分布柱状图 参数: stats: analyze_yolo_labels的输出结果 class_names: 可选的类别名称列表 fig, axes plt.subplots(2, 2, figsize(15, 10)) subsets [train, val, test, total] for ax, subset in zip(axes.flat, subsets): if not stats[subset]: continue classes sorted(stats[subset].keys()) counts [stats[subset][cls] for cls in classes] if class_names: classes [class_names[int(cls)] for cls in classes] ax.bar(classes, counts) ax.set_title(f{subset.capitalize()} Set Distribution) ax.tick_params(axisx, rotation45) plt.tight_layout() plt.savefig(label_distribution.png) plt.close()使用示例与输出解读典型使用流程# 使用示例 if __name__ __main__: # 替换为您的实际路径 label_dir path/to/your/dataset/labels # 可选添加有意义的类别名称 names [person, car, bicycle, dog, cat] stats analyze_yolo_labels(label_dir) plot_label_distribution(stats, names) # 打印详细统计 for subset in [train, val, test]: print(f\n{subset.upper()} Set:) for cls, count in sorted(stats[subset].items()): cls_name names[int(cls)] if names else cls print(f{cls_name}: {count} samples) print(\nTOTAL:, stats[total])输出示例TRAIN Set: person: 1245 samples car: 892 samples bicycle: 156 samples VAL Set: person: 312 samples car: 223 samples bicycle: 39 samples TOTAL: {person: 1557, car: 1115, bicycle: 195}同时会生成包含四个子图的分布图表直观展示数据分布情况。从统计到决策数据优化实战策略识别和处理类别不平衡当统计显示严重类别不平衡时如某些类别样本不足其他类的1/10可考虑解决方案对比表方法适用场景实现难度效果过采样少数类小规模数据集低可能过拟合数据增强所有情况中提升泛化性类别权重中等不平衡低需调参分层采样验证集划分中保证分布一致推荐优先尝试的数据增强技术# 使用albumentations的典型增强组合 import albumentations as A transform A.Compose([ A.HorizontalFlip(p0.5), A.RandomBrightnessContrast(p0.2), A.ShiftScaleRotate(p0.3), A.RandomSizedBBoxSafeCrop(height640, width640, p0.5) ], bbox_paramsA.BboxParams(formatyolo))子集分布一致性检查健康的数据集应满足训练集/验证集/测试集的类别分布相似测试集至少占总数据10-20%验证集足够大以可靠评估模型检查脚本def check_distribution_consistency(stats): 检查各子集分布一致性 subsets [train, val, test] class_ratios {} for cls in stats[total]: ratios [] for subset in subsets: total sum(stats[subset].values()) if total 0: continue ratios.append(stats[subset][cls] / total) if len(ratios) 1 and max(ratios) - min(ratios) 0.15: print(f警告: 类别 {cls} 在不同子集中分布差异过大) class_ratios[cls] ratios return class_ratios高级统计与质量检查扩展边界框尺寸分析添加以下功能可分析目标尺寸分布def analyze_bbox_sizes(label_root): 统计边界框尺寸分布 sizes [] label_path Path(label_root) for subset in [train, val, test]: subset_dir label_path / subset if not subset_dir.exists(): continue for label_file in subset_dir.glob(*.txt): with open(label_file, r) as f: for line in f: parts line.strip().split() if len(parts) 5: continue w, h float(parts[3]), float(parts[4]) sizes.append((w, h)) # 转换为像素面积假设图像尺寸为640x640 areas [w * h * 640 * 640 for w, h in sizes] plt.hist(areas, bins50) plt.xlabel(BBox Area (pixels)) plt.ylabel(Count) plt.title(Object Size Distribution) plt.savefig(bbox_sizes.png) plt.close()常见标注问题检测扩展脚本以检测潜在问题def detect_label_issues(label_root): 检测潜在的标注问题 issues { empty_files: 0, invalid_coords: 0, tiny_boxes: 0 # 面积小于10像素 } label_path Path(label_root) for subset in [train, val, test]: subset_dir label_path / subset if not subset_dir.exists(): continue for label_file in subset_dir.glob(*.txt): with open(label_file, r) as f: lines f.readlines() if not lines: issues[empty_files] 1 continue for line in lines: parts line.strip().split() if len(parts) ! 5: issues[invalid_coords] 1 continue try: x, y, w, h map(float, parts[1:5]) if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): issues[invalid_coords] 1 elif w * h * 640 * 640 10: # 假设图像640x640 issues[tiny_boxes] 1 except ValueError: issues[invalid_coords] 1 return issues在实际项目中这套工具帮助我发现过验证集完全缺失某个关键类别的问题也识别出过标注人员将卡车和货车混为一类导致的模型混淆。数据质量是模型效果的天花板而好的分析工具就是确保这个天花板足够高的第一步。