当前位置: 首页 > news >正文

TT100K数据集类别不平衡?手把手教你用Python筛选并重划分(保留45类实战)

TT100K数据集类别不平衡解决方案Python实战指南当你第一次打开TT100K数据集时可能会被其庞大的图片数量震撼——train文件夹6105张test文件夹3071张other文件夹更是多达7641张。但兴奋过后细看类别分布问题就来了某些交通标志类别只有寥寥几张图片而其他类别却堆积如山。这种极端不平衡的数据分布直接训练模型效果往往惨不忍睹。1. 理解TT100K数据集的核心问题TT100K数据集全称Tsinghua-Tencent 100K是清华大学与腾讯联合发布的交通标志识别数据集。它包含上百种不同类型的交通标志但分布极不均匀数量差异悬殊部分常见标志有上千张图片而稀有标志可能只有个位数样本原始划分不合理train/test/other的划分方式不符合实际训练需求标注格式复杂原始标注信息需要额外处理才能用于主流框架我在处理这个数据集时发现直接使用原始划分训练出的模型在小样本类别上准确率几乎为零。经过多次实验总结出以下关键数据清洗原则数据清洗黄金法则删除样本量不足的类别往往比保留它们更能提升整体模型性能2. 环境准备与数据统计首先确保你的Python环境已安装以下必要库pip install numpy pandas pillow matplotlib opencv-python数据集目录结构通常如下tt100k_2021/ ├── annotations/ ├── other/ ├── test/ └── train/2.1 统计类别分布创建analyze_tt100k.py脚本统计每个类别的图片数量import os import json from collections import defaultdict def count_categories(data_dir): with open(os.path.join(data_dir, annotations.json)) as f: anno json.load(f) cat_count defaultdict(int) for img_id, img_info in anno[imgs].items(): for obj in img_info[objects]: cat_count[obj[category]] 1 return sorted(cat_count.items(), keylambda x: x[1], reverseTrue) if __name__ __main__: data_root tt100k_2021 counts count_categories(data_root) print(Top 10 categories by count:) for cat, cnt in counts[:10]: print(f{cat}: {cnt}) print(\nCategories with 100 samples:) under_100 [(cat, cnt) for cat, cnt in counts if cnt 100] for cat, cnt in under_100: print(f{cat}: {cnt})执行后会输出类似这样的结果Top 10 categories by count: pl100: 1243 pl120: 987 pl80: 876 [...] Categories with 100 samples: pm20: 23 ph4: 15 [...]2.2 可视化分析添加可视化代码更直观理解数据分布import matplotlib.pyplot as plt def plot_category_distribution(counts, threshold100): categories [x[0] for x in counts] counts [x[1] for x in counts] plt.figure(figsize(12, 6)) plt.bar(range(len(categories)), counts) plt.axhline(ythreshold, colorr, linestyle--) plt.xticks(range(len(categories)), categories, rotation90) plt.xlabel(Category) plt.ylabel(Count) plt.title(TT100K Category Distribution) plt.tight_layout() plt.savefig(category_distribution.png) plt.show()3. 数据清洗与类别筛选基于统计结果我们决定只保留样本量≥100的类别。以下是具体实现步骤3.1 创建类别过滤函数def filter_categories(data_dir, min_samples100): with open(os.path.join(data_dir, annotations.json)) as f: anno json.load(f) # 统计有效类别 valid_cats set() cat_count defaultdict(int) for img_id, img_info in anno[imgs].items(): for obj in img_info[objects]: cat_count[obj[category]] 1 valid_cats {cat for cat, cnt in cat_count.items() if cnt min_samples} print(fKeeping {len(valid_cats)} categories with ≥{min_samples} samples) # 过滤标注 new_anno {imgs: {}, types: anno[types]} kept_imgs 0 for img_id, img_info in anno[imgs].items(): valid_objs [obj for obj in img_info[objects] if obj[category] in valid_cats] if valid_objs: new_img_info img_info.copy() new_img_info[objects] valid_objs new_anno[imgs][img_id] new_img_info kept_imgs 1 print(fKept {kept_imgs} images with valid categories) return new_anno, valid_cats3.2 保存过滤后的标注def save_filtered_annotations(annotations, output_path): with open(output_path, w) as f: json.dump(annotations, f, indent2) print(fFiltered annotations saved to {output_path}) # 使用示例 filtered_anno, valid_cats filter_categories(tt100k_2021) save_filtered_annotations(filtered_anno, tt100k_2021/filtered_annotations.json)4. 数据集重新划分策略经过过滤后我们需要将数据重新划分为train/val/test三部分。推荐以下比例数据集比例图片数量示例Train70%~6800Val20%~1900Test10%~10004.1 划分实现代码import random import shutil def split_dataset(data_dir, output_dir, valid_cats, ratios(0.7, 0.2, 0.1)): # 确保输出目录存在 os.makedirs(output_dir, exist_okTrue) for subset in [train, val, test]: os.makedirs(os.path.join(output_dir, subset), exist_okTrue) # 收集所有有效图片路径 img_paths [] for subset in [train, test, other]: subset_dir os.path.join(data_dir, subset) for img_file in os.listdir(subset_dir): if img_file.endswith(.jpg): img_id os.path.splitext(img_file)[0] if img_id in filtered_anno[imgs]: img_paths.append((img_id, os.path.join(subset_dir, img_file))) # 随机打乱并划分 random.shuffle(img_paths) total len(img_paths) train_end int(total * ratios[0]) val_end train_end int(total * ratios[1]) # 复制文件 for i, (img_id, src_path) in enumerate(img_paths): if i train_end: dst train elif i val_end: dst val else: dst test shutil.copy(src_path, os.path.join(output_dir, dst, f{img_id}.jpg)) print(fDataset split complete: {total} images) print(fTrain: {train_end}, Val: {val_end-train_end}, Test: {total-val_end})4.2 划分后验证为确保划分质量建议检查每个子集的类别分布是否均衡是否有图片损坏标注文件是否正确对应def verify_split(output_dir, filtered_anno): # 检查图片完整性 for subset in [train, val, test]: subset_dir os.path.join(output_dir, subset) print(f\nVerifying {subset}:) img_files [f for f in os.listdir(subset_dir) if f.endswith(.jpg)] print(fTotal images: {len(img_files)}) # 检查随机样本 sample random.sample(img_files, min(5, len(img_files))) for img_file in sample: img_id os.path.splitext(img_file)[0] try: img Image.open(os.path.join(subset_dir, img_file)) img.verify() print(f{img_file}: OK, {len(filtered_anno[imgs][img_id][objects])} objects) except Exception as e: print(f{img_file}: Error - {str(e)})5. 高级技巧与优化建议5.1 处理剩余类别的策略对于被过滤掉的小样本类别可以考虑数据增强对剩余样本应用旋转、色彩变换等迁移学习先在大类上预训练再微调小类分层采样确保每个batch包含所有类别样本5.2 性能优化技巧处理大规模数据集时这些技巧可以节省时间# 使用多进程加速文件复制 from multiprocessing import Pool def copy_file(args): src, dst args shutil.copy(src, dst) def parallel_copy(file_pairs, workers4): with Pool(workers) as p: p.map(copy_file, file_pairs)5.3 常见问题排查问题现象可能原因解决方案标注文件缺失路径错误检查annotations.json路径图片数量不符过滤条件太严格调整min_samples阈值内存不足一次加载所有图片改用生成器分批处理6. 完整流程整合将所有步骤整合为可执行脚本process_tt100k.py#!/usr/bin/env python3 Complete TT100K dataset processing pipeline import os import json import random import shutil from collections import defaultdict from PIL import Image from multiprocessing import Pool # [之前定义的所有函数...] def main(): data_dir tt100k_2021 output_dir tt100k_processed min_samples 100 print(Step 1: Analyzing category distribution...) filtered_anno, valid_cats filter_categories(data_dir, min_samples) print(\nStep 2: Saving filtered annotations...) save_filtered_annotations(filtered_anno, os.path.join(output_dir, annotations.json)) print(\nStep 3: Splitting dataset...) split_dataset(data_dir, output_dir, valid_cats) print(\nStep 4: Verifying results...) verify_split(output_dir, filtered_anno) print(\nProcessing complete!) if __name__ __main__: main()执行这个脚本后你将获得一个结构清晰、类别平衡的数据集可直接用于模型训练。在我的实际项目中经过这样的处理后模型在测试集上的mAP提升了约15-20%特别是小样本类别的识别准确率有了显著改善。
http://www.rkmt.cn/news/1373773.html

相关文章:

  • Odin插件深度实践:Unity编辑器效率提升与工作流重构
  • 麒麟KYLINOS声音设置进阶:用命令行玩转‘寻光’主题、单声道和侦听模式
  • 拯救老软件!Windows 10/11高DPI屏幕下界面模糊、错位的终极修复指南
  • 在国产麒麟V10上手动编译Zabbix-Agent,我踩过的坑和最佳实践
  • 告别U盘!用Samba在Ubuntu 22.04上给Windows建个‘云盘’(保姆级图文)
  • 保姆级排查:CentOS7 GNOME桌面黑屏,从tty2终端一步步救回图形界面
  • CVE-2017-0144漏洞原理与企业级SMB安全加固指南
  • 基于一致性哈希的 Harness 有状态路由
  • crAPI靶场实战:API安全漏洞深度解析与Burp Suite攻防技巧
  • 随机数值线性代数:从子空间嵌入到机器学习优化实战
  • 张正友标定法到底在干啥?用大白话和Python代码带你理解相机畸变与内参矩阵
  • 从科研到落地:手把手教你用Python预处理PhysioNet ECG数据(附PTB-XL实战代码)
  • 棋牌网站渗透测试实战:弱口令与SQL注入组合利用
  • 【ChatGPT】未来先进CMP(化学机械抛光)设备及其控制系统软硬件架构的深度拆解、爆炸图、信息图、C++代码框架
  • Armv8-A架构扩展:安全防护与高性能计算解析
  • K6 HTTP性能测试实战:请求控制、指标可信与检查可追溯
  • JMeter、ab、Postman并发压测原理与避坑指南
  • 2026监狱门厂家怎么选:监狱门/防弹门窗/防爆墙/防爆窗/防爆门/防辐射门/隔声门/隧道防护门/密闭窗/工业门/选择指南 - 优质品牌商家
  • 告别驱动冲突:在预装NVIDIA驱动的Deepin V23 Beta3上干净安装指定版本显卡驱动
  • Mac上mitmproxy HTTPS抓包实战:证书配置与Python脚本化
  • Unity生存游戏底层架构:资源约束与状态耦合引擎设计
  • Unity生存游戏开发:ECS架构下的物理化生存系统实现
  • 2026年5月更新:广东定制卡通公仔实力厂家的选型指南与趋势洞察 - 2026年企业推荐榜
  • 2026可靠婚庆公司推荐榜:启动道具租赁、奠基仪式、奠基石、婚庆公司、婚庆策划公司、封顶仪式策划公司、庆典公司选择指南 - 优质品牌商家
  • AICore:达芬奇架构的心脏怎么跳
  • 解决Ubuntu 22.04下载慢/连不上?一键脚本+图形化界面,双管齐下搞定DNS和APT源
  • 北京游学机构哪家好?包含鸟巢水立方路线的研学机构推荐 - 品牌2025
  • 2026扁钢技术全解析:兰州三通/兰州不锈钢板/兰州不锈钢管/兰州中厚板/兰州保温管/兰州冷板/兰州变径/兰州圆钢/选择指南 - 优质品牌商家
  • Arm嵌入式开发中的代码覆盖率分析实践
  • Fiddler HTTPS抓包失败原因与证书信任机制详解