第四章 数据集准备与预处理:工业落地的第一步

说实话,很多搞算法的朋友觉得模型结构才是核心。但我做了这么多年工业项目,可以负责任地告诉你——数据准备才是真正决定项目生死的关键。模型剪枝量化再牛,数据不对,一切都是白搭。

这一章,我们就来聊聊工业场景下,YOLOv11的数据集到底该怎么准备。

4.1 工业数据集格式:COCO vs YOLO

工业项目里,最常见的标注格式就两种:COCO和YOLO。我见过不少团队在这上面栽跟头,所以先把这个讲清楚。

对比维度 COCO格式 YOLO格式
标注文件 单个JSON文件 每张图片一个TXT
坐标表示 左上角(x,y)+宽高 中心点(x,y)+宽高(归一化)
类别定义 JSON内categories数组 数字索引(0,1,2...)
适用场景 通用检测、实例分割 YOLO系列原生格式
工业落地难度 中等(需解析JSON) 低(直接读取)

我个人习惯:工业项目直接用YOLO格式。为什么?因为产线上的数据量动不动几十万张,COCO的单个JSON文件一旦损坏,整个标注就废了。YOLO格式每张图独立,出问题只影响一张,容错性好太多。

核心要点:YOLOv11原生支持YOLO格式。如果你手头是COCO数据,记得做格式转换。我一般用下面这个脚本搞定:

import json
import os

def coco_to_yolo(coco_json_path, output_dir):
    with open(coco_json_path, 'r') as f:
        coco_data = json.load(f)
    
    # 建立图片ID到文件名的映射
    img_map = {img['id']: img['file_name'] for img in coco_data['images']}
    
    # 建立类别ID到连续索引的映射
    cat_map = {cat['id']: idx for idx, cat in enumerate(coco_data['categories'])}
    
    # 逐张图片转换
    for ann in coco_data['annotations']:
        img_id = ann['image_id']
        img_file = img_map[img_id].replace('.jpg', '.txt')
        
        # COCO: [x, y, w, h] → YOLO: [cx, cy, w, h] 归一化
        x, y, w, h = ann['bbox']
        img_w = coco_data['images'][img_id]['width']
        img_h = coco_data['images'][img_id]['height']
        
        cx = (x + w/2) / img_w
        cy = (y + h/2) / img_h
        nw = w / img_w
        nh = h / img_h
        
        cat_id = cat_map[ann['category_id']]
        
        with open(os.path.join(output_dir, img_file), 'a') as f:
            f.write(f"{cat_id} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}\n")

我曾经踩过的坑:COCO的bbox是[x, y, width, height],而YOLO需要的是归一化的中心点坐标。直接复制粘贴坐标,模型训练出来检测框全偏。嗯,那次排查了我整整两天。

4.2 数据标注工具:选对工具事半功倍

工业场景下,标注工具的选择直接影响效率。我推荐三个:

  • LabelImg:轻量级,适合小团队快速上手。Python写的,安装简单。
  • LabelStudio:支持多人协作,适合中大型项目。可以标注分类、检测、分割。
  • CVAT:英特尔出品,功能最全。支持自动标注、半自动标注,工业级首选。

我个人在产线上用得最多的是CVAT。为什么?因为它支持半自动标注——先用一个预训练模型跑一遍,人工只修正错误框。效率能提升3-5倍。

小技巧:标注时,类别名称统一用英文小写+下划线。比如"defect_scratch"、"defect_dent"。中文路径在Linux服务器上经常出编码问题,别问我怎么知道的。

4.3 数据增强策略:Mosaic与MixUp

工业数据往往不够多样。比如产线上拍的零件,角度、光照都差不多。这时候就需要数据增强来"造"数据。

Mosaic增强

YOLOv4开始引入的Mosaic,说白了就是把4张图拼成1张。这样做的好处:

  • 小目标检测能力提升(拼图后目标相对变小)
  • 背景多样性增加
  • BN层统计更稳定

YOLOv11里Mosaic默认是开启的。但注意,训练最后10-20个epoch建议关掉。为什么?因为拼图后的分布和真实场景有差异,一直用会让模型学偏。

# YOLOv11超参数配置示例
# hyp.yaml
mosaic: 1.0        # 前80% epoch开启
mosaic_close_epoch: 10  # 最后10个epoch关闭

MixUp增强

MixUp更狠——两张图按比例混合,标签也按比例混合。比如0.7的猫+0.3的狗,标签就是[0.7, 0.3]。

我在项目中遇到过一个问题:MixUp虽然能提升泛化能力,但会让模型收敛变慢。所以我的建议是:数据量少于1万张时开MixUp,超过1万张可以关掉。

工业落地经验:数据增强不是越多越好。我见过一个团队开了10种增强,结果模型在产线上误检率飙升。记住:增强的目的是模拟真实变化,不是制造不存在的情况。

4.4 数据加载器定制:让GPU吃饱

工业场景下,数据加载往往是性能瓶颈。GPU算力再强,数据喂不进去也是白搭。

YOLOv11的数据加载器已经做得不错了,但有几个点需要定制:

  1. 多线程加载:workers数量设为CPU核心数的2-4倍。我一般设8或16。
  2. 预取队列:开启prefetch,让CPU提前准备下一批数据。
  3. 缓存策略:小数据集(<1万张)可以全量缓存到内存,IO速度提升10倍。
# 自定义数据加载器示例
from torch.utils.data import DataLoader
from ultralytics.data import YOLODataset

class IndustrialDataset(YOLODataset):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 缓存图片到内存
        self.cache_images = True
    
    def load_image(self, i):
        # 自定义加载逻辑
        img = super().load_image(i)
        # 工业相机拍的图可能带EXIF旋转信息
        # 这里做自动旋转校正
        return self._fix_exif_rotation(img)

# 使用示例
loader = DataLoader(
    IndustrialDataset(...),
    batch_size=32,
    num_workers=8,      # 多线程加载
    prefetch_factor=4,  # 预取队列
    pin_memory=True     # 锁页内存加速
)

注意:num_workers不是越大越好。我试过设32,结果CPU被打满,GPU反而等数据。一般8-16就够用了。具体多少,跑一次看CPU利用率就知道了。

4.5 本章知识体系总览

下面这张图,把数据准备的全流程串起来了。你可以把它当作一个checklist,做项目时对照着来。

YOLOv11数据准备全流程 YOLOv11 数据准备全流程 ① 数据采集 ② 格式转换 ③ 数据标注 ④ 数据增强 ⑤ 加载器定制 ⑥ 模型训练 关键要点 • 工业场景优先使用YOLO格式,容错性好 • Mosaic增强在最后10个epoch关闭 • 数据加载器num_workers设为8-16,配合prefetch_factor=4 避坑指南 • 标注文件路径不要用中文,Linux服务器会报错 • 数据增强不是越多越好,模拟真实变化才是关键

数据准备这块,说白了就是"磨刀不误砍柴工"。我见过太多项目,模型结构调得飞起,结果数据有问题,最后全白干。嗯,这一章的内容足够你应付90%的工业场景了。记住:好的数据,是模型剪枝量化的地基。