COCO 的 [50, 60, 120, 80] 转成 YOLO 的 0 0.171875 0.208333 0.187500 0.166667,
回算 3/3 一致。COCO 从 1 编号、YOLO 从 0 编号——差 1 就全错位。
上一节把名字理顺了。这一节把标注导出成训练能吃的格式,重点讲两个最容易出错的地方。
一、导出就是一次格式翻译
标注工具里存的是一套结构,训练框架要的是另一套结构。导出就是中间那次翻译。 翻译要动三样东西:坐标的表示方式、类别的编号方式、文件怎么组织。三样里任何一样错了, 训练都能跑起来,但结果全错。 这就是这一节的核心风险:格式错误不会报错,只会让 loss 降不下去。你会在那里调学习率、换优化器、 怀疑模型结构,而真正的问题在坐标多除了一个宽度。 所以导出的正确做法不是「点了导出就完事」,而是导出之后回算一遍——把导出的数按逆公式算回去, 跟原始值比。差值小于容差,才算转对了。
二、COCO 和 YOLO 差在哪
COCO 的 bbox 是 [x, y, w, h]:左上角的像素坐标,加上宽和高。单位是像素,数值范围是图像尺寸。
YOLO 的是 cx cy w h:中心点坐标加上宽高,而且全部除以图像宽高归一化到 0 到 1。
所以转换公式是:cx = (x + w/2) / W,cy = (y + h/2) / H,w' = w / W,h' = h / H。
两个坑:一是中心点(COCO 给左上角,YOLO 要中心,忘了加 w/2 就整体偏移半个框);
二是除以谁(cx 除以图宽、cy 除以图高,除反了框会被拉伸)。
第三个坑是类别编号:
COCO 的 category_id 从 1 开始,YOLO 的 class 从 0 开始。 直接照抄就整体错一位——
所有汽车被当成行人,所有行人被当成红绿灯。
三、常见格式一览
不同框架吃不同格式,导出前先确认下游要什么:
| 格式 | 坐标表示 | 典型用途 |
|---|---|---|
| COCO JSON | x,y,w,h 像素 | 通用交换、评测 |
| YOLO txt | cx,cy,w,h 归一化 | YOLO 系列训练 |
| VOC XML | xmin,ymin,xmax,ymax | 老项目、Pascal VOC |
| CSV | 自定义列 | 交付、人工核对 |
| 同一个标注,四种写法。 所以「导出」这件事不能只点一次——要按下游需求导出对应的那一份, | ||
| 并且留一份 COCO 原样存档。 | ||
| 存档那份很重要:COCO 是最中立的中间格式,其他格式基本都能从它转出去,反过来不一定。 | ||
| 所以项目一开始就存 COCO,后面要什么都能转。 |
四、在 MakeSense 里导出
📋 实操清单(要在浏览器里点):
第一步,点左侧或顶部的 Actions 菜单,选 Export Annotations。
第二步,选格式。MakeSense 支持 COCO、YOLO、VOC、CSV、TFRecord 等几种。
做检测选 COCO 或 YOLO,做分类选 CSV。
第三步,如果选 YOLO,工具会打成一个 zip——里面是每张图一个 txt,加一个 classes.txt 记录类别顺序。
这个 classes.txt 的顺序就是类别编号,别丢。
第四步,下载后立刻跑一次回算检查。这一步不能省。
🐍 沙箱等价物:转换和回算见 Demo。
沙箱里点不了导出按钮,但「转完对不对」是纯数学——回算一遍,差值小于千分之一就算过。
这个检查脚本应该放进每次导出的流程里,而不是出了问题才写。
五、动手 Demo:COCO 转 YOLO:三个框回算 3/3 一致,类别编号要减 1
造一份 COCO 格式的标注(640×480 的图、3 个框、2 个类别),按公式转成 YOLO 的 class cx cy w h,
写出文件,再把 YOLO 的数按逆公式算回去,跟 COCO 的原始值比对。
for a in coco[u'annotations']:
x, y, w, h = a[u'bbox']
cx = (x + w / 2.0) / W # 注意加 w/2:COCO 给左上角
cy = (y + h / 2.0) / Hh
lines.append(u'%d %.6f %.6f %.6f %.6f'
% (cat2i[a[u'category_id']], cx, cy,
w / float(W), h / float(Hh)))
# 回算:YOLO 反推回 COCO,看跟原值差多少
bx = (cx - ww / 2.0) * W
by = (cy - hh / 2.0) * Hh
实跑输出:
--------------------------------------------------------------------
导出数据:坐标从 COCO 换到 YOLO,差一个除法和一个中心点
--------------------------------------------------------------------
源格式 COCO(bbox = x, y, 宽, 高,单位像素)
目标格式 YOLO(cx, cy, 宽, 高,全部归一化到 0 到 1)
图像尺寸 640 × 480
标注数 3 个
转换公式:cx = (x + w/2) / W,cy = (y + h/2) / H,w' = w / W,h' = h / H。
**两个容易错的地方:COCO 给的是左上角加宽高,YOLO 要的是中心点。**
另一个是类别编号:COCO 从 1 开始,YOLO 从 0 开始,差 1 就全错位。
标注 id COCO YOLO
-----------------------------------------------------------------------------
1 [50.0, 60.0, 120.0, 80.0] 0 0.171875 0.208333 0.187500 0.166667
2 [300.0, 200.0, 60.0, 150.0] 1 0.515625 0.572917 0.093750 0.312500
3 [420.0, 320.0, 180.0, 100.0] 0 0.796875 0.770833 0.281250 0.208333
写出来的文件(每行一个框,对应一张图的 txt):
0 0.171875 0.208333 0.187500 0.166667
1 0.515625 0.572917 0.093750 0.312500
0 0.796875 0.770833 0.281250 0.208333
转完必须回算一遍,确认没有精度损失:
回算一致 3/3
最后核对三件事,一件都不能少:
① 框数 COCO 里 3 个,txt 里也得 3 行
② 类别映射 COCO 从 1 开始,YOLO 从 0 开始,差 1 是最常见的错
③ 取值范围 归一化后所有数都该在 0 到 1 之间,超了就是算错
**这三条都是「不检查也不会报错」的那一类——训练能跑,但框全歪了,loss 就是不降。**
done -> _out_39f.txt
表里三行,COCO 和 YOLO 一一对应。
看第一个:[50, 60, 120, 80] → 0 0.171875 0.208333 0.187500 0.166667。
手算一遍验证:cx = (50 + 60) / 640 = 0.171875,w' = 120 / 640 = 0.1875。
加的是 w/2 不是 w。
类别那一列:COCO 的 category_id 是 1 和 2,YOLO 里变成 0 和 1。
这一位差最容易漏,而且漏了不报错。
回算那一段是关键:把 YOLO 的数按逆公式还原成 COCO,跟原始值比,3/3 一致(容差千分之一)。
这就是「导出之后必须自检」的具体做法。
最后三项核对里,第三项「取值范围」也很好用:归一化之后所有数都该在 0 到 1 之间。
如果出现大于 1 的数,一定是忘了除或者除错了。 一条断言就能拦住。
30 秒实验
- 故意把
cx的公式改成x / W(忘了加w/2),再跑回算,看偏差是多少。 偏差正好是半个框宽,这就是「整体偏移」的样子。 - 故意把
cx和cy的除数对调,看回算对不上的是哪几个数。 体会一下「除反了」和「忘了加」在数值上的区别。 - 把类别编号改成直接从 1 开始(不减 1),看文件长什么样。 它完全合法,训练也能跑——这就是最难发现的那种错。
常见误区
- 「点了导出就完事」。格式错误不报错,只让 loss 降不下去。必须回算自检。
- 「COCO 和 YOLO 只是括号写法不同」。差的是中心点、归一化、类别起始值三件事,每件都能让训练失效。
- 「只存一种格式就够了」。建议始终存一份 COCO 当中间格式,要别的从它转;反过来不一定转得回去。
自测三问(点开对答案)
1. COCO 的 bbox 和 YOLO 的坐标差在哪三件事上? —— 左上角对中心点、像素对归一化、类别从 1 开始对从 0 开始。三件里任何一件错了,框都会整体偏掉。 2. 为什么导出后要回算一遍? —— 因为格式错误不会报错,训练照跑但 loss 不降。回算是唯一能自动发现「坐标算错了」的办法。 3. 为什么要留一份 COCO 格式存档? —— 因为 COCO 是最中立的中间格式,其他格式基本都能从它转出去,反过来不一定。 留它等于留了所有可能性。第四章到这里结束:从「为什么标」到「怎么导」,一条线走完了。 第五章开始讲微调——把标注好的数据真正用起来。
- ☐ (本章完,下一节 5.1.1 揭开模型微调的神秘面纱)