news 2026/10/2 8:35:11

草原牦牛行为识别数据集:YOLO+VOC双格式8674张样本实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
草原牦牛行为识别数据集:YOLO+VOC双格式8674张样本实战解析

简介:数据集为草原牦牛行为识别数据集,面向计算机视觉学习者与智慧牧场应用开发者,共8674张jpg图片及对应标注,覆盖吃草、打架、站立、躺、移动、交配等8种行为,可直接用于目标检测模型训练。资源包共2000个文件,其中Annotations文件夹含1999个xml标注文件,labels文件夹含txt标注,另有说明文件,压缩包约694.83MB,图片与标注分目录存放,查找方便。目前已有230人学习下载。标注框总计18423个,各行为类别数量已单独统计,如eating 6897个、standing 3710个、lying 2071个等,便于分析类别分布并划分训练/验证集。YOLO与VOC两种格式可无缝适配YOLOv5/YOLOv8、Faster R-CNN等常见框架,省去格式转换环节,适合快速开展牦牛行为识别实验或作为数据增强的基准数据集。

1. 草原牦牛行为识别数据集:8674张双格式样本能解决的问题不止“认牛”

拿到这个压缩包,先别急着解压。标题里的“草原耗牛行为识别数据集yolo+voc格式8674张8种行为.zip”,点破了三件关键事:图片量是8674张,不是几百张的小样;标注格式是YOLO和VOC双轨;行为类别有8种。这意味着你可以直接拿它训练一个能判断“牛在吃草、站立、行走还是争斗”的检测模型,省掉自己去草原蹲点采集、标注的几个月时间。适合两拨人:一是刚入门目标检测、想拿真实野外数据练手的新手;二是做智慧畜牧或牧场视频监控落地的工程师,拿它当预训练权重或迁移学习的起点。至于标题里的“耗牛”,是“牦牛”的常见笔误,搜索资料和解压后找目录时都留意一下。

2. 先看懂数据:VOC和YOLO双标注到底怎么组织的

2.1 同一批图片,两套标注文件的对应关系

VOC格式沿用Pascal VOC的XML标注,记录的是绝对像素坐标;YOLO格式用同名txt文件,记录归一化后的中心点坐标和宽高。二者描述同一张图里的同一个目标,服务不同年代的工具链:老牌标注软件、检测框架多认VOC,YOLO系列训练默认读txt,所以“双格式”本质是同一份数据给你发了两个版本。

一张图片对应一个XML文件和一个txt文件,文件名通常与图片名一致,只是后缀不同。如果解压后看到Annotations/目录下是XML、labels/目录下是txt,那就是标准的双轨布局;如果只有一个目录,说明压缩包内部其实只有一种原始标注,另一种是脚本生成的。无论哪种,先做文件清点。

2.2 解压后优先检查这四类文件

解压后不要直接开训,先确认下面四类东西是否齐整。

文件类型常见目录/文件名作用
图片images/或JPEGImages/训练与验证输入
VOC标注Annotations/下的.xml绝对坐标、类别名、图片尺寸
YOLO标注labels/下的.txt归一化类别ID与坐标
类别清单classes.txt或obj.names8个行为类的名称与顺序
数据划分train.txt、val.txt或train/val子目录训练集与验证集划分

先写几行命令看目录结构再动手:

unzip -q 草原耗牛行为识别数据集yolo+voc格式8674张8种行为.zip -d yak_dataset cd yak_dataset find . -maxdepth 2 -type d | sort

unzip -q静默解压,避免刷屏;解压到yak_dataset目录避免污染当前路径。find只看两层目录,确认有没有images、labels、Annotations这类顶层目录。如果解压后是一堆散文件,说明压缩包没带目录层级,需要自己按文件名前缀归组。

注意,压缩包内的文件名可能包含“耗牛”字样,与标题一致,但脚本和目录名里最好统一改成“yak”,免得后续路径处理踩坑。

2.3 统计8类行为的数据分布,先看长尾

“8种行为”听起来平均,实际上大概率不平均。野外采集场景天然偏斜:站立和吃草的样本可能占六成,争斗、饮水这类短时行为可能只有几百张。不统计直接训,模型会被高频行为带偏。

写个脚本快速统计YOLO标注里的类别分布:

from collections import Counter from pathlib import Path labels_dir = Path("yak_dataset/labels") counter = Counter() total_boxes = 0 for txt in labels_dir.glob("*.txt"): for line in txt.read_text().splitlines(): if line.strip(): cls_id = int(line.split()[0]) counter[cls_id] += 1 total_boxes += 1 print("total boxes:", total_boxes) for cls_id, cnt in sorted(counter.items()): print(f"class {cls_id:2d}: {cnt:5d} {cnt / total_boxes * 100:5.1f}%")

遍历全部txt,读取每行第一个数字作为类别ID,用Counter计数。输出能直接看出哪一类占比不足5%,这就是之后训练时要重点加权的对象。

这个脚本不依赖任何第三方库,纯标准库就能跑。如果某个类别的框数只有几百,而最多的类别有三四千,说明长尾严重,训练时的class_weights或数据增强要单独处理。

3. 从VOC转YOLO:一份能直接跑的转换脚本

3.1 为什么非转不可:两种坐标体系的差异

很多开源数据集只给VOC格式,而YOLO训练要求标签是txt。就算这个压缩包已经给了双格式,也经常因为“txt是生成的、不完整”或者“缺val划分”,需要自己重转一遍。

VOC的XML记录的是绝对坐标,比如xmin=120, ymin=80, xmax=340, ymax=260,单位是像素;YOLO记录的是相对坐标,中心点和宽高都除以图片宽度与高度,取值范围在0到1之间。坐标系原点和表示方式都不同,转换公式必须准确:

  • 中心点x = (xmin + xmax) / 2 / 图片宽
  • 中心点y = (ymin + ymax) / 2 / 图片高
  • 宽度 = (xmax - xmin) / 图片宽
  • 高度 = (ymax - ymin) / 图片高

图片尺寸必须从XML的<size>字段读取,不能自己用PIL现量。原因有两个:一是量8000多张图耗时,二是如果图片被预处理过(比如去EXIF旋转后另存),XML里记录的原始尺寸可能和实际磁盘尺寸不一致,量了反而错。

3.2 转换脚本与最小用法

下面是我常用的转换脚本,标准库即可运行:

import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_path, save_dir, class_list): tree = ET.parse(xml_path) root = tree.getroot() img_width = int(root.find("size/width").text) img_height = int(root.find("size/height").text) lines = [] for obj in root.iter("object"): name = obj.find("name").text if name not in class_list: continue cls_id = class_list.index(name) bndbox = obj.find("bndbox") xmin = float(bndbox.find("xmin").text) ymin = float(bndbox.find("ymin").text) xmax = float(bndbox.find("xmax").text) ymax = float(bndbox.find("ymax").text) # 防止越界,但先记录原始值 xmin = max(0.0, min(xmin, img_width - 1)) xmax = max(0.0, min(xmax, img_width - 1)) ymin = max(0.0, min(ymin, img_height - 1)) ymax = max(0.0, min(ymax, img_height - 1)) if xmax <= xmin or ymax <= ymin: continue # 宽高为负的坏框直接丢弃 x_center = (xmin + xmax) / 2.0 / img_width y_center = (ymin + ymax) / 2.0 / img_height width = (xmax - xmin) / img_width height = (ymax - ymin) / img_height # 强制clip到[0, 1]区间,防止浮点误差 x_center = max(0.0, min(x_center, 1.0)) y_center = max(0.0, min(y_center, 1.0)) width = max(0.0, min(width, 1.0)) height = max(0.0, min(height, 1.0)) lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}") if not lines: return False # 空标签文件 save_path = Path(save_dir) / (Path(xml_path).stem + ".txt") save_path.write_text("\n".join(lines) + "\n") return True if __name__ == "__main__": class_list = ["grazing", "standing", "walking", "running", "lying", "fighting", "drinking", "scratching"] # 以压缩包内 classes.txt 实际内容为准,这里只是示例顺序 xml_dir = Path("yak_dataset/Annotations") txt_dir = Path("yak_dataset/labels") txt_dir.mkdir(exist_ok=True) converted = 0 empty = 0 for xml_file in xml_dir.glob("*.xml"): ok = voc_to_yolo(xml_file, txt_dir, class_list) if ok: converted += 1 else: empty += 1 print("empty or invalid:", xml_file.name) print(f"converted {converted} files, {empty} empty results")

脚本先从XML的size/width和size/height拿到图片宽高,这是转换精度关键。然后遍历每个<object>节点,取类别名和坐标框,做坐标防越界裁剪,再套用归一化公式。

逻辑说明:max(0.0, min(xmin, img_width - 1))把框限制在图片有效像素范围内,避免xmax超出宽度导致归一化大于1。xmax <= xmin的判断会过滤掉标注坏框,这类框进入训练会造成损失函数异常。最后强制clip到[0,1]区间,是防浮点误差,不是隐藏问题——如果大量样本触发clip,说明原始标注批量越界,得回头查标注工具。

参数说明:class_list的顺序就是训练时的类别ID顺序,必须与data.yaml的names保持一致。脚本默认跳过未出现在class_list中的类别名。

3.3 转换后必做的三类自检

转换结束并不代表能直接训练,建议按以下顺序检查:

第一,抽样对比XML与txt内容。选一张样本,打开XML看原始坐标,再打开对应txt,手动算一遍公式结果是否吻合。批量转换里最容易犯的错是图片宽高取错,这类错会让所有框偏移一个固定比例。

第二,检查空标签数量。野外数据存在“图片里确实没有目标”的情况,这类图片在YOLO训练里应该被剔除或单独处理,直接放进去会影响评估指标。脚本里已经统计了empty数量,如果超过1%,先看是不是XML解析路径写错了。

第三,检查类别ID是否越界。8种行为对应的类别ID范围是0到7,如果txt里出现8或更大值,说明class_list与XML里的类别名对不上。用上一章的统计脚本再跑一次,看类别分布是否正常。

4. 用YOLO把8类行为训起来:环境、训练命令与参数

4.1 环境搭建与预训练权重

推荐直接用ultralytics库,它是YOLOv5到YOLO11的训练入口,命令行和Python API都能用。环境安装很简单:

pip install ultralytics

如果在国内网络环境,把pip源换成清华镜像,否则下载依赖容易超时。验证安装:

python -c "from ultralytics import YOLO; print(YOLO.__name__)"

输出YOLO说明库可用。图形化依赖版本坑多在PyTorch与CUDA版本不匹配,CPU环境训练8674张图会非常慢,一张640x640的图片在CPU上可能要跑好几秒,建议至少用一块带8GB显存的GPU。

预训练权重下载要认准官方渠道。YOLOv8s的权重文件约22MB,YOLOv8m约50MB,这是官方发布的基础模型权重,不是从其他机构二次训练的版本。训练命令会自动下载,也可以手动放weight/目录避免反复拉取。这个数据集类别是动物行为,与COCO的80类差异很大,但用预训练权重做初始化仍然能显著加速收敛,新手别从随机权重开始训。

4.2 data.yaml怎么配置

YOLO训练的数据配置用一个YAML文件搞定:

path: /data/yak_dataset train: images/train val: images/val names: 0: grazing 1: standing 2: walking 3: running 4: lying 5: fighting 6: drinking 7: scratching

path是数据集根目录的绝对路径;train和val是相对于path的图片目录路径;names的类别顺序必须与训练标签txt里的ID一致。这里写的是示例类别名,具体以压缩包内classes.txt为准。

如果数据集的划分不是目录结构,而是两个txt文件(每行一个图片路径),可以把train写成train.txt的路径,ultralytics也支持train: train.txt这种写法。

4.3 训练命令与关键参数

数据准备好了,训练命令非常短:

yolo detect train \ data=yak.yaml \ model=yolov8s.pt \ epochs=100 \ imgsz=640 \ batch=16 \ workers=4 \ patience=15 \ device=0

model=yolov8s.pt表示用YOLOv8s结构并加载COCO预训练权重;如果写yolov8s.yaml,则表示只用结构、随机初始化,收敛慢且最终精度通常更低。imgsz=640是训练输入尺寸,图片喂进网络会被缩放到640x640;batch=16是每批次样本数,显存不够就降到8或4。patience=15是早停机制,连续15个epoch验证集mAP不提升就自动结束,省时间。

参数建议值说明
modelyolov8s.pt / yolov8m.pt数据量不大,s起步;精度不足再升m
epochs100~2008类行为不算复杂,100轮足够
imgsz640牦牛目标较大,不必强行上1280
batch16 / 8 / 4按显存调整,显存不足先降batch
workers4数据加载线程数,过高反而慢
device0指定GPU编号,CPU训练写cpu

batch和imgsz的关系要单独说:imgsz增大会显著增加显存占用,如果显存只有8GB,imgsz=640, batch=16可能刚好,imgsz=1280, batch=16大概率爆显存。野外目标检测场景里,目标尺寸通常占画面的比例不小,不需要为了小目标强行拉高分辨率。

训练开始的第一个epoch会较慢,因为要做数据加载、缓存、归一化,之后的每个epoch速度会稳定。如果某个epoch突然卡住很久,多半是workers太高把CPU打满,或者磁盘读取速度跟不上。

训练结束后在runs/detect/train/目录下会生成best.pt和last.pt。best.pt是验证集mAP最高的权重,推理、导出都用它;last.pt是最后一个epoch的权重,通常用于断点续训。

5. 避坑与常见问题:数据解压、标签和训练实录

5.1 解压后找不到标签目录,路径多了一层

现象:解压后发现图片在一个层级很深的目录里,labels/和预期路径对不上,训练报AssertionError: Label class 8 exceeds nc=8之类的错误。

原因:压缩包内目录通常带项目名嵌套,比如草原耗牛/yolo/labels和草原耗牛/yolo/images,直接把路径写死到yak_dataset/labels找不到文件。

解决:先用find . -name "*.txt" | head定位所有标签文件的实际路径,再用软链接或目录整理脚本把images和labels提到同一层。

5.2 转换脚本里类别顺序与训练配置不一致,loss降不下去

现象:训练loss前期下降,但验证mAP一直很低,或者某个类别的精确率接近0。

原因:VOC转YOLO时给XML里的行为名手动编号,和YOLO训练时的names顺序不一致。比如XML里“fighting”排在第三位,脚本里却是第5位,模型学到的全是错位标签。

解决:永远从classes.txt读取类别顺序来生成class_list,不要自己手敲顺序。代码里先读文件再传列表:

class_list = Path("yak_dataset/classes.txt").read_text().splitlines() print(class_list)

这样转出的txt与训练配置天然一致。这也是“玄学”返工最常见的原因,标签错位不会报错,只会让模型成绩很难看。

5.3 坐标越界与坏框导致训练中BN崩溃

现象:训练到第几十个epoch,loss突然变为NaN,或者验证阶段一张图上出现几百个重叠预测框。

原因:VOC转换时没有处理xmax超出图片宽度的坏框。这些框的存在会让归一化坐标超出[0,1],YOLO训练时的损失函数计算出现异常。加上某些图片自带的标注框宽高为0,也会造成类似问题。

解决:转换脚本里必须clip坐标并过滤空宽高的框。同时转换完成后,写一条命令扫描labels中所有非空txt,检查每行的坐标值是否都在0到1之间,超出就定位对应XML人工复核。

5.4 行为类别长尾严重,模型把所有牛都认成“站立”

现象:验证集总mAP显示0.6以上,但具体到“争斗”“喝水”这类细粒度行为,AP只有0.1。打开预测图,几乎所有的牛都被识别成高频类别。

原因:数据集中8种行为的框数量极度不均。高频行为的梯度主导了模型更新,低频行为的特征没有被充分学习。这是行为识别数据集的通病,野外采集天然偏斜。

解决:训练前用第2章的统计脚本输出类别占比,对低频类别做两件事。第一,在yolo detect train配class_weights,对低频类别加大损失权重;第二,检测图片里低频行为样本做复制粘贴增强,把这些行为实例贴到其他场景里生成新标注。

5.5 图片EXIF旋转导致标注偏移

现象:训练过程正常,但推理时预测框位置与牛的实际位置整体偏移,尤其是竖拍照片。

原因:部分手机或运动相机拍摄的图片包含EXIF旋转信息。XML标注坐标是基于原始感光矩阵的像素位置,而YOLO训练前ultralytics会按EXIF信息把图片转正,导致坐标与新图片尺寸不匹配。

解决:这是VOC转YOLO最常见的隐蔽问题。转换脚本读取图片宽高时,应该先按EXIF校正后保存图片,再读校正后的实际宽高。如果数据集是网络公开数据,也可能已经统一校正过,但仍建议抽样打印几张图片的实际尺寸与XML里的size字段对比,不一致就批量校正。

6. 验证与进阶:从训练完到野外视频流的最后一公里

6.1 看混淆矩阵,别只盯mAP

mAP是一个聚合指标,8个类的均值掩盖了单个行为的问题。训练出的best.pt在验证集上跑一次混淆矩阵:

yolo detect val \ model=runs/detect/train/best.pt \ data=yak.yaml

结束后去runs/detect/val/看confusion_matrix.png。重点关注“争斗”“奔跑”这类同类易混行为是否大量互相误判。如果两类的混淆度超过20%,把它们合并成一个行为类别或者补充数据,比调参更有效。

6.2 把模型接进视频推理

野外场景最终是视频流实时分析。ultralytics的推理接口支持视频文件直接输入:

yolo detect predict \ model=runs/detect/train/best.pt \ source=ranch_video.mp4 \ conf=0.35 \ iou=0.5 \ save=True

conf=0.35是置信度阈值,野外监控建议比公测常用的0.25高一点,减少误检;iou=0.5是NMS的交并比阈值,两个高重叠候选框会被合并。结果视频输出到runs/detect/predict/。

如果要在边缘设备或NVR后端跑,先把权重导出为TensorRT引擎或ONNX格式,推理速度提升明显。导出命令是:

yolo export model=runs/detect/train/best.pt format=onnx opset=12 yolo export model=runs/detect/train/best.pt format=engine device=0

TensorRT导出依赖GPU型号,换设备后需要重新导出,这是部署时必须记住的坑。

6.3 下一步:数据增强、难例挖掘与部署

训练收敛后想再往上提精度,最有效的不是继续拉长epochs,而是做两件数据侧的功夫。一是针对牦牛多目标拥挤的场景做Mosaic增强,默认开启,但把mosaic概率调低到0.5左右,否则小批量数据里融合太多样本反而让模型学糊涂。二是收集预测置信度在0.3到0.6之间的“难例”,把真实标注拉出来合并进训练集再训一轮,这比盲目增加图片数量更划算。

我自己的教训是:行为识别项目里,80%的提升来自把数据和标签弄干净,剩下20%才是模型和超参。先把压缩包里每一张图和每一条标签都检查过,再去调imgsz和anchor,顺序别搞反。希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 8:34:35

基于Transformer的时间序列预测Python源码解析与调优

简介&#xff1a;一套基于Transformer模型的时间序列预测Python源码项目&#xff0c;主要面向需要完成课程期末大作业、毕业设计或入门深度学习时序建模的高校学生与开发者。项目已在本地编译运行通过&#xff0c;难度适中&#xff0c;且经过助教老师审定&#xff0c;能够满足课…

作者头像 李华
网站建设 2026/10/2 8:33:07

中文NER实战:BERT-BiLSTM-CRF源码解析与可复现训练指南

简介&#xff1a;本资源面向中文命名实体识别&#xff08;NER&#xff09;的入门与进阶学习者&#xff0c;提供一套基于PyTorch实现的BERT-BiLSTM-CRF完整项目&#xff0c;适合毕业设计、期末大作业与课程设计场景&#xff0c;也便于新手通过注释理解模型原理。压缩包共22个文件…

作者头像 李华
网站建设 2026/10/2 8:33:05

YOLOv10焊缝缺陷检测实战:从工艺约束到轻量化部署

简介&#xff1a;本资源是一套面向工业质检场景的YOLOv10焊缝质量检测完整方案&#xff0c;适用于计算机视觉初学者、自动化检测工程师及智能制造领域研究者&#xff0c;解决焊缝缺陷&#xff08;如裂纹、气孔、未熔合等&#xff09;的快速识别与分类问题。压缩包共2000个文件&…

作者头像 李华
网站建设 2026/10/2 8:29:59

时薪两美元喂大顶尖算法,亚马逊运营二十一年的秘密工厂突然关停

时薪两美元喂大顶尖算法&#xff0c;亚马逊运营二十一年的秘密工厂突然关停 你可能很难想象&#xff0c;过去二十年里那些看似无所不能的顶尖科技&#xff0c;最初其实是由一群躲在屏幕后面、赚着几美分零钱的普通人&#xff0c;一单单「手工」捏出来的。 更讽刺的是&#xff0…

作者头像 李华