简介:这份资源是面向计算机视觉开发者与深度学习研究者的野生动物目标检测数据集,适用于野外固定视角水域场景下的动物识别与检测模型训练。数据覆盖大角斑羚、大象、长颈鹿、黑斑羚、捻角羚、羚羊、犀牛、角马、斑马共9类动物,图片清晰且未做增强,标注总框数达19285个,其中黑斑羚3907框、捻角羚2780框、大角斑羚2642框,类别分布较为均衡。压缩包共约2000个文件,以1999个xml标注文件和1个说明txt为主,整体约371.87MB,同时提供VOC与YOLO两种标注格式,方便直接接入主流检测框架。资源按JPEGImages、Annotations、labels三个文件夹分别存放8089张jpg图片及对应的xml、txt标注,目录结构清晰,便于快速划分训练集与验证集。目前已有460人学习下载,适合用于目标检测课程实践、算法对比实验或野生动物保护相关的检测项目。
1. 8089 张野外动物图 + 双格式标注:这份数据集到底能拿来干什么
如果你正在做野生动物目标检测,大概率经历过两件事:一是公开数据集要么只有 COCO 那种通用类别,要么是单一物种、单一场景,训出来的模型换个机位就崩;二是好不容易找到一份标注,结果只有 YOLO 格式,想转 VOC 做对比实验还得自己写脚本。这份 8089 张、9 种动物、19285 个标注框的野外动物数据集,恰好卡在这两个痛点上——它同时给了 YOLO 的 txt 和 VOC 的 xml,图片来自野外水域固定视角摄像,没有做数据增强,属于"生图直出"。
它适合谁?做野生动物监测、保护区红外相机/固定机位分析、生态类毕设或课程设计的人,可以直接拿它当 baseline 训练集;做 YOLO 入门、想跑通"自己数据集训练"全流程的人,它的类别分布不均(黑斑羚 3907 框 vs 犀牛 1123 框)正好能让你练手处理长尾问题。不适合谁?想要高分辨率航拍、夜间红外、或者需要实例分割掩码的人,这份是纯检测框,别指望它给你 mask。
2. 先看清数据分布:9 类动物的框数、场景与选型理由
拿到一份数据集,我第一件事不是急着写训练脚本,而是先把标注统计跑出来。原因很简单:类别不平衡、框的尺度分布、图片分辨率,这三个东西直接决定你后面要不要做重采样、要不要改 anchor、要不要切图。这份数据集的标签名是英文小写,和常见中文叫法对应关系容易搞混,先对齐。
2.1 标签名与中文对照、框数分布
数据集给的 9 个标签是eland、elephant、giraffe、impala、kudu、oryx、rhino、wildebeest、zebra。注意eland是大角斑羚(不是麋鹿),impala是黑斑羚,kudu是捻角羚,oryx是剑羚/羚羊,wildebeest是角马。这几个羚字辈的英文名,新手极容易在写类别映射时写错,一旦names顺序和标注里的 class id 对不上,训出来的模型会把长颈鹿认成斑马,而且 loss 还降得很正常,属于典型的"玄学翻车"。
| class id | 标签名 | 中文 | 框数 |
|---|---|---|---|
| 0 | eland | 大角斑羚 | 2642 |
| 1 | elephant | 大象 | 1525 |
| 2 | giraffe | 长颈鹿 | 2067 |
| 3 | impala | 黑斑羚 | 3907 |
| 4 | kudu | 捻角羚 | 2780 |
| 5 | oryx | 羚羊 | 1269 |
| 6 | rhino | 犀牛 | 1123 |
| 7 | wildebeest | 角马 | 待补全 |
| 8 | zebra | 斑马 | 待补全 |
提示:项目正文里
wildebeest和zebra的框数被截断了,实际使用时以你解压后自己统计的结果为准,不要照抄任何二手数字。
从已知框数看,最多的黑斑羚 3907,最少的犀牛 1123,比例约 3.5:1。这个不平衡程度不算极端,但足以让模型偏向黑斑羚。我一般会先算一遍每类的框数,再决定要不要用copy_paste或者类别加权。选型理由:如果你只是做课程设计、要求 mAP 过得去,直接训就行;如果是要发论文或者做实际部署,长尾处理绕不开。
2.2 为什么这份数据适合做固定视角检测
图片来自野外水域固定视角摄像,意味着相机位置、焦距、光照角度相对稳定,背景里水草、水面反光、岸边植被的分布比较一致。这对检测是好事:模型不用花大量容量去记"这个场景长什么样",能更专注在动物本身的纹理和轮廓上。但反过来,它也有代价——泛化到其他机位会掉点。所以我的建议是:拿它做训练集没问题,但验证集最好也来自同一批固定视角,别拿它去直接评估一个要部署到无人机上的模型。
另外,图片"无增强"这点很关键。很多公开数据集会预先做翻转、裁剪、色彩抖动,你拿到手时分布已经被改过。这份是原始图,意味着数据增强的控制权在你手里,你可以按自己的训练策略决定要不要 mosaic、mixup。常见做法是:YOLO 训练时开 mosaic,但验证时关掉,保证 mAP 可比。
3. 目录结构与格式校验:解压后先跑这三步
压缩包里是 3 个文件夹,分别放图片、xml、txt。标准结构应该是JPEGImages(8089 张 jpg)、Annotations(8089 个 xml)、labels(8089 个 txt)。三个数量必须一致,任何一个对不上,说明有图没标注或者有标注没图,训练时要么报错要么静默丢样本。我一般解压后先跑一遍校验脚本,把问题提前暴露。
3.1 用 Python 校验图片、xml、txt 三者是否一一对应
import os img_dir = "JPEGImages" xml_dir = "Annotations" txt_dir = "labels" # 取文件名(不含扩展名)做集合比对 imgs = {os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(".jpg")} xmls = {os.path.splitext(f)[0] for f in os.listdir(xml_dir) if f.endswith(".xml")} txts = {os.path.splitext(f)[0] for f in os.listdir(txt_dir) if f.endswith(".txt")} print("图片数:", len(imgs)) print("xml数:", len(xmls)) print("txt数:", len(txts)) # 找出缺失项 print("有图无xml:", imgs - xmls) print("有xml无图:", xmls - imgs) print("有图无txt:", imgs - txts) print("有txt无图:", txts - imgs)逻辑说明:用集合差集找出三类文件里对不上的部分。参数上,os.path.splitext去掉扩展名,保证 jpg/xml/txt 同名才能配对。如果输出里三个集合大小都是 8089 且差集为空,说明数据完整。如果有缺失,先别急着训,缺标注的图要么删掉,要么补标,否则 YOLO 读到一个没有对应 txt 的图会直接跳过,你以为训了 8089 张,实际可能只训了 8000 张。
3.2 校验 YOLO txt 的坐标范围与类别 id
YOLO 格式每行是class_id x_center y_center width height,坐标是归一化到 0~1 的。常见翻车是坐标越界(大于 1 或小于 0),或者 class_id 超出 0~8 的范围。跑下面这段能一次性查出来。
import os txt_dir = "labels" bad_lines = [] class_count = {} for f in os.listdir(txt_dir): if not f.endswith(".txt"): continue with open(os.path.join(txt_dir, f)) as fp: for i, line in enumerate(fp): parts = line.strip().split() if len(parts) != 5: bad_lines.append((f, i, "字段数不对")) continue cid = int(parts[0]) coords = list(map(float, parts[1:])) class_count[cid] = class_count.get(cid, 0) + 1 if cid < 0 or cid > 8: bad_lines.append((f, i, "class_id越界")) if any(c < 0 or c > 1 for c in coords): bad_lines.append((f, i, "坐标越界")) print("类别框数统计:", class_count) print("异常行数:", len(bad_lines)) for b in bad_lines[:10]: print(b)逻辑说明:逐行解析,先查字段数是否为 5,再查 class_id 是否在 0~8,最后查四个坐标是否落在 0~1。class_count顺便帮你统计每类框数,和前面表格对照,能验证wildebeest、zebra的真实数量。参数上,如果你的类别数不是 9,把cid > 8改成cid > num_classes - 1。异常行建议打印前 10 条定位,不要一次性刷屏。
3.3 VOC xml 与 YOLO txt 的对应关系
VOC 的 xml 里存的是绝对像素坐标xmin, ymin, xmax, ymax,YOLO 的 txt 是归一化中心点加宽高。两者可以互相转换,公式是:
x_center = (xmin + xmax) / 2 / img_w y_center = (ymin + ymax) / 2 / img_h width = (xmax - xmin) / img_w height = (ymax - ymin) / img_h这份数据集两种格式都给了,省了你转换的功夫。但要注意:xml 里的name是字符串标签,txt 里是数字 id,两者的映射顺序必须和你的data.yaml里names列表一致。我见过有人 xml 用字母序、txt 用另一套序,结果训练时标签全错位,loss 看着正常,mAP 惨不忍睹。校验方法:随便抽一张图,把 xml 的框画出来,再把 txt 的框按上面公式还原画出来,两个框应该完全重合。
4. 从 VOC 到 YOLO 训练:data.yaml 配置与训练脚本
数据校验通过后,下一步是把它喂给 YOLO。不管你是用 YOLOv5、v8 还是 v11,核心都是三样:data.yaml、图片路径、标签路径。这份数据集已经分好JPEGImages和labels,但 YOLO 默认期望的是images/train、images/val、labels/train、labels/val这种结构,所以要么改目录,要么在 yaml 里直接指到你的文件夹。
4.1 划分训练集与验证集
8089 张图,我一般按 8:2 划,训练 6471、验证 1618。注意要按图片划分,不能按框划分,否则同一张图的框被拆到两个集合,验证集就泄漏了。下面脚本按文件名随机划分并生成两个 txt 列表。
import os import random random.seed(42) # 固定种子,保证可复现 img_dir = "JPEGImages" imgs = [os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(".jpg")] random.shuffle(imgs) split = int(len(imgs) * 0.8) train, val = imgs[:split], imgs[split:] with open("train.txt", "w") as f: for name in train: f.write(os.path.join(img_dir, name + ".jpg") + "\n") with open("val.txt", "w") as f: for name in val: f.write(os.path.join(img_dir, name + ".jpg") + "\n") print("训练:", len(train), "验证:", len(val))逻辑说明:random.seed(42)保证每次划分一致,方便复现实验。参数上,0.8是训练比例,数据量小可以调到 0.9,但验证集别少于 500 张,否则 mAP 波动大。生成的 txt 里存的是图片绝对或相对路径,YOLO 读这个列表找图,再根据路径替换images为labels找标签,所以你的目录命名最好规范,别用中文路径。
4.2 data.yaml 的写法与 names 顺序
path: /your/dataset/root train: train.txt val: val.txt nc: 9 names: 0: eland 1: elephant 2: giraffe 3: impala 4: kudu 5: oryx 6: rhino 7: wildebeest 8: zebra逻辑说明:nc是类别数,必须等于names的长度。names的顺序必须和 txt 里的 class_id 严格对应,这份数据集如果 txt 是按字母序排的,那上面这个顺序大概率对;但保险起见,用 3.2 的脚本打印class_count,看每个 id 对应的框数是否和表格一致,就能反推顺序对不对。参数上,path写数据集根目录,train/val写相对路径。如果你的 YOLO 版本要求images/train结构,就把JPEGImages软链接或复制成images/train,labels对应labels/train。
4.3 启动训练与关键参数
yolo detect train \ data=data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ workers=4 \ project=runs/wildlife \ name=baseline逻辑说明:model=yolov8n.pt是 nano 版,适合先跑通流程;确认没问题再换yolov8s或yolov8m。imgsz=640是常见输入尺寸,如果你的原图分辨率远大于 640,小目标(比如远处的羚羊)会被缩没,这时候要么切图,要么把imgsz提到 1280,但显存要够。batch=16是保守值,显存 8G 以上可以往上加。workers=4是数据加载线程,Windows 下如果报错就设成 0。epochs=100对 8000 张图通常够收敛,但类别不平衡时可能需要更多轮。
注意:训练前确认你的 YOLO 环境能正常 import,PyCharm 里装 ultralytics 后如果报
No module named 'ultralytics',多半是解释器选错了,检查项目解释器是不是你 pip 安装的那个。
5. 避坑与排查:标注、类别、显存这三类问题最容易翻车
这一章是我自己踩过的坑,按"现象 → 原因 → 解决"写,你对照着排查能省不少时间。
5.1 训练 loss 正常但 mAP 极低
现象:训练几十轮,box_loss、cls_loss 都在降,但验证 mAP 一直在 0.01 附近。原因:最常见的是names顺序和 txt 里的 class_id 错位,模型学的是"id 0 是长颈鹿",但你评估时按"id 0 是大角斑羚"去算,全错。解决:用 3.2 的脚本打印每类框数,和表格对照;再抽一张图,把预测框和真实框画在一起看类别文字对不对。另一个可能是图片和标签路径没对上,YOLO 静默跳过了大部分样本,实际只训了几百张。
5.2 报 "No labels found" 或训练集为空
现象:启动训练后提示找不到标签,或者train: 0 images。原因:YOLO 默认按路径替换找标签,比如图片路径是JPEGImages/xxx.jpg,它会去找labels/xxx.txt,但你的 txt 可能在labels/下还有子目录,或者命名不一致。解决:确认JPEGImages和labels同级,且文件名(不含扩展名)完全一致。如果目录结构特殊,用train.txt里写绝对路径,并在 yaml 里显式指定labels路径(部分版本支持)。
5.3 显存溢出 CUDA out of memory
现象:训练到一半报 OOM。原因:imgsz或batch太大,或者workers太多导致内存泄漏。解决:先把batch减半,再把imgsz从 640 降到 512 试;如果还不行,检查是不是开了 mosaic 且图片本身很大。另一个隐蔽原因是验证阶段同时加载模型和缓存,可以设cache=False。
5.4 类别不平衡导致小类几乎检不出
现象:黑斑羚、捻角羚 mAP 还行,犀牛、羚羊几乎为 0。原因:犀牛只有 1123 框,模型偏向多数类。解决:在 yaml 里加类别权重(部分版本支持class_weights),或者用copy_paste增强小类,再或者对多数类做欠采样。我一般先试增强,不行再动采样,因为采样会改变数据分布,影响泛化。
5.5 xml 和 txt 标注不一致
现象:用 VOC 格式训和用 YOLO 格式训,同一模型 mAP 差很多。原因:两种格式的框可能有细微差异,比如 xml 里有的框在 txt 里被过滤了(面积过小),或者坐标取整方式不同。解决:抽 20 张图,把两种格式的框都画出来叠一起看,差异大的样本单独查。如果只是取整误差,可以忽略;如果是漏标,以 xml 为准重新生成 txt。
6. 进阶:用这份数据做长尾实验与部署前验证
跑通 baseline 之后,这份数据集真正的价值在于它的长尾分布和固定视角特性,可以拿来做一些有意思的验证。我一般会做两件事:一是用类别重加权对比 mAP 变化,二是导出 ONNX 做推理速度测试,确认部署可行性。
先说长尾实验。你可以复制一份data.yaml,在训练时加cls_pw(类别权重)或者用 focal loss 替换默认的 BCE。对比实验设计:baseline 用默认配置,实验组用加权,其他参数完全一致,跑 3 个种子取平均。重点看小类(rhino、oryx)的 AP 提升,如果小类涨了但大类掉太多,说明权重过头,回调。这个流程能帮你理解"不平衡到底影响多大",比看论文直观。
再说部署验证。训练完的best.pt导出 ONNX:
yolo export model=runs/wildlife/baseline/weights/best.pt format=onnx imgsz=640导出后用 onnxruntime 跑一张测试图,对比 PyTorch 和 ONNX 的输出差异,一般 cosine 相似度要大于 0.99 才算正常。如果差异大,检查导出时的opset版本和动态轴设置。这一步是部署前的后悔药——很多人训完直接上板子,结果发现算子不支持,回头改模型结构,浪费一周。
最后说一个我自己的习惯:每次拿到新数据集,不管多急,我都会先跑一遍 3.1 和 3.2 的校验脚本,把图片数、标注数、类别分布打印出来存档。有一次我跳过这步直接训,训完发现验证集里混进了训练集的图,mAP 虚高 20 个点,白高兴一场。从那以后我每次划分数据集都强制走一遍校验,确认 train 和 val 的文件名没有交集。这份 8089 张的野生动物数据集,结构清晰、双格式齐全,只要你把类别映射和路径这两关过了,剩下的就是调参的事。希望帮到你。
本文还有配套的精品资源,点击获取