☰
黑熊检测数据集:COCO转YOLO格式,1009张图训练全指南
2026/9/28 8:03:38 网站建设 项目流程

简介:一套面向黑熊(bear)目标检测任务的数据集,从COCO2017数据集中筛选并提取相关图像,整理为可直接用于YOLO等主流检测算法的标准格式。压缩包共3028个文件,大小约214.28MB,其中包含1009张jpg原图、1009个xml标注文件,以及1010个txt标注文件。txt标签内包含类别与目标框坐标,适合YOLO系列直接读取;xml标签采用VOC格式,记录图像尺寸与目标位置,便于在Faster R-CNN、SSD等框架中灵活切换。两种标注格式各有侧重,免去开发者自行编写转换脚本的麻烦。数据集类别统一为bear,图片源自真实场景,尺寸与背景多样,适合目标检测初学者练习单类别检测,也可用于算法效果对比或补充缺少黑熊样本的项目数据。目前已有155人学习,资源按原图与标签分类存放,结构清晰,下载解压后即可快速接入常见检测流程。

1. 黑熊检测数据集:1009张图、txt+xml双格式,拿来就能训

这份黑熊检测数据集是我见过比较省事的野生动物检测训练素材。它从COCO2017里把bear这一类全部抽出来,图片还是COCO原始的jpg文件,标注则单独转成了txt和xml两种格式,数量1009张,类别名统一叫bear。也就是说你不用再写转换脚本、不用自己爬图,下载解压后按YOLO的目录要求摆好,改一下data.yaml就能开训。适合这几类人:第一次跑YOLO目标检测、想用现成数据走通全流程的新手;做野生动物监测、熊类识别项目但缺标注数据的从业者;以及想验证YOLOv5或YOLOv8在自己显卡上效果如何的玩家。下面我从文件结构、标签格式、训练参数到踩坑记录,把这套数据从头到尾拆给你看。

2. 数据文件与标注格式:COCO原始标注如何落成bear标签

2.1 从文件名到目录:先搞清这份数据长什么样

解压后你会看到大量类似000000091844.jpg这种命名的图片,这是COCO官方的补零命名法,12位数字编号,不需要也没必要改名。图片全部来自COCO2017的train2017和val2017,数据集作者已经按bear类过滤好了,所以直接看内容就是各种场景下的熊:树林里的、雪地里的、远处的、近景的,光照和遮挡情况都比较丰富。

目录组织一般长这样:

bear_dataset/ ├── images/ │ ├── train/ │ │ ├── 000000091844.jpg │ │ └── ... │ └── val/ │ ├── 000000361341.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── 000000091844.txt │ │ └── ... │ └── val/ │ └── ... └── annotations/ ├── bear_train.xml └── bear_val.xml

images和labels是按train/val子目录对应的,txt和jpg文件名一致,这是YOLO系工具默认的读取方式。如果你拿到的压缩包不是这个结构,也简单,自己写两行脚本按文件名前缀归类就行。要特别注意:图片和标签文件名必须严格同名,后缀可以不同,但主名一旦对不上,训练时会直接跳过这张图,而且不报错,这个我后面避坑章节会细讲。

2.2 txt与xml:两种标签格式的字段对照

同一份标注,为什么给两种格式?因为不同工具链吃的格式不一样。YOLO系列(v5/v8)原生读txt,每行一个目标;而VOC系的工具、部分可视化脚本和标注平台只认xml。下面这张表能把两种格式的差异看清楚:

项目YOLO txtVOC xml
文件后缀.txt.xml
坐标基准归一化,范围0~1像素绝对值
目标格式每行一个目标<object>块
类别表示类别id(数字)类别名(字符串)
中心点写法x_center y_center左上角+右下角xmin ymin xmax ymax
适用场景YOLO训练、推理预处理数据可视化、VOC工具链、二次标注

txt的每一行固定是五个数,顺序是:类别id、中心点x、中心点y、框宽、框高。这五个数全部除以图片宽高做了归一化,所以无论原图是1920还是640,训练时都不用管绝对像素。xml则是标准的PASCAL VOC结构,<name>标签里写的是bear这个字符串,<bndbox>里是四个绝对像素坐标。你如果要做样本校验或者框可视化,xml读起来更直观;如果要喂给YOLO,txt更直接。

这份数据集最省事的地方在于:你不需要从零写转换器,两种格式都给你备好了。但我的建议是,训练用txt,可视化检查用xml,各取所长。

2.3 COCO json转YOLO txt:一个可复用的转换脚本

虽然这份数据已经转好了,但实际项目中你大概率还要往数据里补充自己的熊类图片,那就要自己写转换。我从COCO官方json里抽取bear类并转成YOLO txt的脚本如下,直接可跑:

import json import os from pathlib import Path def coco_to_yolo(coco_json, img_dir, out_label_dir, cat_names=['bear']): with open(coco_json, 'r') as f: coco = json.load(f) # 建立category名称 -> 新id的映射,这里只有bear一种,新id恒为0 cat_id_map = {} target_ids = set() for cat in coco['categories']: if cat['name'] in cat_names: target_ids.add(cat['id']) cat_id_map[cat['id']] = 0 # 单类统一映射到0 if not target_ids: raise ValueError('没有找到目标类别') # 先按image_id建索引 img_info = {img['id']: img for img in coco['images']} anns_by_img = {} for ann in coco['annotations']: if ann['category_id'] not in target_ids: continue image_id = ann['image_id'] if image_id not in anns_by_img: anns_by_img[image_id] = [] anns_by_img[image_id].append(ann) os.makedirs(out_label_dir, exist_ok=True) for image_id, anns in anns_by_img.items(): img = img_info[image_id] img_path = os.path.join(img_dir, img['file_name']) if not Path(img_path).exists(): continue w, h = img['width'], img['height'] txt_path = os.path.join(out_label_dir, Path(img['file_name']).stem + '.txt') lines = [] for ann in anns: cx, cy, bw, bh = ann['bbox'] # coco的bbox是[x, y, width, height] # 转成归一化坐标并做边界裁剪 x_center = max(0.0, min(1.0, (cx + bw / 2) / w)) y_center = max(0.0, min(1.0, (cy + bh / 2) / h)) box_w = max(0.0, min(1.0, bw / w)) box_h = max(0.0, min(1.0, bh / h)) lines.append(f'0 {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}') with open(txt_path, 'w') as f: f.write('\n'.join(lines)) coco_to_yolo('instances_train2017.json', 'train2017', 'labels_train')

这段脚本的核心是三个步骤:先建类别映射,把COCO原始的category_id统一改成新编号0;再遍历所有标注,只保留目标类别;最后把COCO的[x, y, width, height]格式换算成YOLO的[x_center, y_center, width, height]并除以图片宽高。参数说明:coco_json是COCO的标注文件路径,img_dir是图片目录,out_label_dir是txt输出目录,cat_names传你想提取的类别名列表,默认只取bear。注意COCO的bbox坐标是左上角起点,不是中心点,很多新手在这里翻车,换算时要记得加上宽高的一半。

xml的生成逻辑其实类似,只是要拼VOC的XML结构,用xml.etree.ElementTree就能写。这部分的重点只有一个:坐标不要除错。COCO的宽高和YOLO的宽高都指框本身,但COCO是像素值,YOLO是比例值,换算时分子分母都必须来自同一张图片的实际宽高。

3. 用YOLOv5训练黑熊检测:目录组织、配置与训练命令

3.1 数据集目录与data.yaml配置

拿到了txt标签和jpg图片,接下来把它们组织成YOLOv5能直接读的格式。我一般会在YOLOv5项目根目录下新建一个bear_data文件夹,然后把数据集按下面的目录结构摆放:

bear_data/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ ├── bear.yaml └── test/

train和val的比例,官方默认是--train和--val两个参数分开指定,没有强制比例。我建议按9:1或8:2划,1009张图不算多,验证集留100张左右就够看效果,留太多训练数据会不够用。划分时用随机抽样,但要注意同一个场景的连续帧最好别同时出现在train和val里,否则你的验证分数会偏乐观。

然后写数据集配置文件bear.yaml:

# bear.yaml train: bear_data/images/train val: bear_data/images/val nc: 1 names: ['bear']

这里nc表示类别数量,黑熊检测只有bear一类,所以是1。names列表里的顺序必须和txt标签里的类别id对应,因为我们的txt里全部写的是0,所以names的第一位就是bear。如果你的标签里出现了1、2这样的id,说明类别数不止一个,这个后面避坑部分会再说。注意YOLOv5里路径可以写绝对路径也可以写相对于项目根目录的路径,但不要用~/这种符号,容易解析出错。

3.2 训练命令与关键参数

配置写好后,直接用train.py启动训练:

python train.py \ --data bear_data/bear.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 200 \ --workers 4 \ --project runs/bear_train \ --name exp1

命令行参数说明如下:--data指向刚写的yaml文件;--weights填预训练权重,这里用yolov5s.pt,如果你的显卡显存小于6G,可以换yolov5n.pt,精度略降但显存占用少一半;--img是训练分辨率,640是默认值,COCO原图大多在500到800像素之间,640不需要改;--batch根据显存调整,8G显存跑16没问题,8G以下建议降到8;--epochs在数据量少时拉长到200甚至300,因为单类检测收敛快,但更多epoch有助于稳定;--workers是数据加载线程数,Windows下建议设成0,否则容易报DataLoader worker错误。

训练过程中重点看两个东西:一是loss曲线是不是持续下降,二是每个epoch结束时的mAP@0.5有没有明显爬升。如果跑了50个epoch mAP还是零,先别怪数据,大概率是标签出了问题,跳去第4章排查。

3.3 迁移学习的作用:1009张图怎么训出稳定模型

1009张图对目标检测来说不算多,尤其是熊这种在画面中占比变化极大的目标,直接从头训练很容易过拟合。这里的关键是迁移学习:COCO预训练权重里本来就见过bear这个类(COCO 80类包含bear),换句话说模型已经知道熊长什么样,我们做的只是在熊的子集上微调。

我用yolov5s实测下来,预训练权重起训,前50个epoch mAP就会快速爬升到0.8以上,而随机初始化从头训的话,50个epoch可能还在0.5附近挣扎。如果你的场景不是纯黑熊,而是需要区分棕熊、黑熊、北极熊,那建议把nc改成对应类别数,并重新整理txt标签,模型仍能利用预训练权重里的通用特征。

另外一个很实用的小技巧:显存不足时,可以打开--multi-scale参数,让YOLO在训练时随机使用0.5到1.5倍的分辨率缩放。这个参数对1000张量级的小数据集特别有帮助,相当于免费做了多尺度数据增强,能明显缓解小目标熊漏检的问题,代价是训练速度下降约两三成。

4. 避坑:黑熊数据训练中的五个常见问题

4.1 类别id错位:训练不报错但mAP一直为零

现象:训练过程正常,loss也在降,但每个epoch的mAP都是0,验证集一张熊都检测不出来,logs里还偶尔出现Target is out of bounds的警告。

原因:COCO原始标注里bear的category_id是22(按COCO的80类编号),有人顺手把这个22直接写进了txt。但你的yaml里nc: 1,模型只认为有类别0,于是id=22的标签要么越界被丢弃,要么被强行当成背景处理,模型根本学不到有效目标。

解决:把数据集里所有txt的第一列强制改成0,用一条命令搞定:sed -i 's/^[0-9]* /0 /' labels/train/*.txt。或者回到转换脚本,在写txt前统一做cat_id_map[ann['category_id']] = 0。我拿到任何数据集的第一件事就是抽查3到5个txt文件,看类别id有没有超出nc-1范围。

4.2 图片无对应标签导致训练中断或loss异常

现象:训练跑到一半报assert ... labels.shape == (n, 5)错误,或者某几个epoch loss突然变成nan。

原因:COCO2017里并不是每张含有bear的图都有有效的bear标注,有些图里的熊被严重遮挡,标注时被过滤掉了,于是出现了只有jpg没有txt的情况。YOLOv5在做数据加载时会读取同名的txt,发现文件不存在或内容为空,就会在缓存里报错。

解决:训练前先做一次标签完整性检查,用脚本把所有只有图片没有txt的文件剔除:

from pathlib import Path for split in ['train', 'val']: img_dir = Path(f'bear_data/images/{split}') lbl_dir = Path(f'bear_data/labels/{split}') for img in img_dir.glob('*.jpg'): txt_path = lbl_dir / (img.stem + '.txt') if not txt_path.exists() or txt_path.stat().st_size == 0: img.unlink() print(f'removed {img.name}')

检查完再删除runs目录下的缓存文件重新训练。这一步对从COCO提取的子集特别重要,COCO官方标注里有不少空标注或极端尺寸的框,不清理干净迟早会咬你一口。

4.3 小目标熊检测不到

现象:验证集mAP@0.5能到0.9,但你拿一张熊在画面远处、占比很小的图去推理,结果什么都没框出来。

原因:1009张图里大尺度的熊占多数,模型对中小目标的召回率天然偏低。另外YOLOv5默认的anchor是基于COCO整体统计出来的,对“熊占画面比例极小”的场景并不适配。

解决:训练时加上--multi-scale做多尺度训练,推理时把--img从640提到960或1280,小目标特征会更明显。还可以在训练后跑一次python utils/anchors.py --data bear_data/bear.yaml --img-size 640重新聚类anchor,把默认anchor换成基于你数据集统计的尺寸,对这张图集实际效果很明显。

4.4 验证集loss反复震荡

现象:训练曲线里验证集loss像锯齿一样上下跳动,训练集loss却稳定下降,mAP波动幅度超过5个点。

原因:1009张图按9:1划分后验证集只有100来张,样本方差太大,每个epoch抽到的验证batch质量各不相同,loss自然会震荡。另一个常见原因是学习率太高,默认的0.01在数据量小时偏激进。

解决:把验证集比例提高到20%(大约200张),同时把--lr0降到0.005或0.001。loss震荡本身不可怕,可怕的是你看不出趋势,所以建议用TensorBoard观察val loss的滑动平均而非原始曲线。200张验证图放在1000张的量级上,既不影响训练,也能让评估指标稳定不少。

4.5 黑熊棕熊的命名混淆

现象:你下载这份数据是想做黑熊检测,但翻开图片发现里面棕熊、黑熊都有,有的图连熊都分不清品种,标签统一叫bear。

原因:COCO2017的bear类别本身没有细分亚种,所有熊科动物都归在bear这一个类下。数据集名字虽然叫黑熊检测,但标注是COCO原生的,没有做品种重标注。

解决:如果你只要黑熊,我的建议是用这份数据做预训练,然后准备一两百张纯黑熊图片微调,或者用主动学习筛选出黑熊样本重新标注。如果你要同时区分黑熊、棕熊、北极熊,那这份数据只能提供通用熊类特征,需要你把标签细分后重训,别指望拿来即用。

5. 验证与进阶:从mAP到误检分析的完整闭环

5.1 用val.py跑一次评估:看懂Precision、Recall与mAP

训练结束后,光看训练日志不够,我会单独用val.py在验证集上正经跑一次评估:

python val.py \ --data bear_data/bear.yaml \ --weights runs/bear_train/exp1/weights/best.pt \ --img 640 \ --batch 16 \ --conf-thres 0.001 \ --iou-thres 0.5

按上面的参数跑完,终端会输出Precision、Recall、mAP@0.5、mAP@0.5:0.95四行数据。怎么解读:Precision是模型框出来的目标里真正是熊的比例,Recall是真实熊里被框出来的比例,两者在conf阈值变化时此消彼长。mAP@0.5是IoU阈值0.5下的平均精度,做工程落地主要看这个;mAP@0.5:0.95是更严格的指标,对框的位置精度敏感,适合用来调优但不作为业务验收标准。

单类检测时,mAP@0.5大于0.9属于正常水平,0.8到0.9说明可用但有小幅误检,低于0.8就要回头查数据了。我把conf阈值设为0.001而不是默认的0.25,是为了把低置信度预测也纳入评估,这样能看清模型的完整召回能力。想省事的话,直接python val.py --data bear_data/bear.yaml --weights best.pt跑默认参数也行,但低阈值跑出来的指标更有参考价值。

5.2 混淆矩阵与误检分析:不止看mAP

mAP只是一个数字,真正告诉你模型哪里不行的是混淆矩阵。训练完在runs/bear_train/exp1/目录下会生成confusion_matrix.png,单类检测时重点看两类:一是bear这一类别的召回率,二是background类别被预测成bear的比例。背景误检率超过10%时,说明模型把树桩、岩石、深色衣物当成了熊,这在野生动物监控场景里很致命。

我的习惯是再从验证集里抽三四十张图,用detect.py批量推理保存结果,然后人工翻一遍:

python detect.py \ --weights runs/bear_train/exp1/weights/best.pt \ --source bear_data/images/val \ --img 640 \ --conf 0.25 \ --save-txt \ --save-conf

--save-txt会把推理结果存成txt,方便你对比预测框和真实框的差异;--save-conf会附上每个框的置信度。翻图时重点找两类问题:熊被框成两半的,说明NMS后处理没合并好;以及背景被框出来的,说明模型学到的特征里混入了环境纹理。这些人工分析比盯着mAP看要实在得多,也是数据集后续扩充时的方向指引。

5.3 数据增强与多尺度:有限数据下的稳定性

1009张图训一个单类检测器,数据增强就不是锦上添花,而是必要手段。YOLOv5训练时默认开启了mosaic、random_perspective、hsv_augment等增强,这些配置在hyp.scratch.yaml里。我在这个数据集上会把mosaic的mosaic_scale从默认的0.5到1.5改成0.3到1.8,让熊在拼接图里的尺寸变化更大,对远近尺度不同的熊更友好。

如果训练环境显存够大(12G以上),我推荐把--img设成800而不是640。这个数据集里的熊很多是远距离拍摄,占画面比例小,800分辨率下小目标对应的像素区域更大,训练出来的模型在实际检测中更稳。代价是训练速度下降约40%,但1000张图的体量,多跑半小时换来几个点的mAP提升,我认为是划算的。

数据增强参数不建议一次改太多。先只开--multi-scale跑一个对比组,再改mosaic参数跑一个对比组,用验证集指标决定去留。这个数据集体量小,一个epoch就一两分钟,多跑几个对比实验的成本很低,但你能清楚地知道每个增强手段到底贡献了多少。

6. 训练前先做标签可视化:一个能省一天排错时间的小习惯

前面说了这么多,有一个动作我强烈建议你每次拿到新数据集都做一遍:把txt标签画回图片上看一眼。很多人标签格式对不对、坐标有没有除错,直到训练完才发现,然后回去查转换逻辑,一天就没了。标签可视化只要十几行代码,却能提前暴露绝大多数标注问题:

import cv2 def draw_yolo_boxes(img_path, txt_path, class_names=['bear']): img = cv2.imread(img_path) h, w = img.shape[:2] with open(txt_path, 'r') as f: lines = f.readlines() for line in lines: parts = line.strip().split() cls_id, cx, cy, bw, bh = int(parts[0]), float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img, class_names[cls_id], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) cv2.imshow('label check', img) cv2.waitKey(0) cv2.destroyAllWindows() draw_yolo_boxes('bear_data/images/train/000000091844.jpg', 'bear_data/labels/train/000000091844.txt')

这段代码将归一化的中心点坐标还原成像素坐标,画框并标注类名,按空格键逐张翻图。检查重点是:框是否紧贴熊的身体而不是只框了头或半个身子;是否存在大量宽高比异常的长条框;以及标签值和图片内容是否对得上。我一般随机抽20到30张,覆盖远景、近景、遮挡几种情况,全部正常才启动训练。

从那以后,我拿到任何数据集的第一件事都是先可视化标签,再谈训练。这个习惯帮我避掉过类别id写错、坐标用成了像素值没归一化、txt和jpg文件名后缀不匹配等至少五种问题,每次省下的都是实打实的半天时间。希望你能把这套数据集玩明白,也把这个检查习惯带进自己的项目里,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询