简介:基于YOLOv8的智慧牧场牲畜异常行为识别系统是一套面向计算机视觉与深度学习方向毕设及课程设计的完整实践项目,聚焦牲畜异常行为的自动检测。压缩包共8个文件,包含3个Python脚本、3个模型权重文件和2个说明文档:脚本覆盖可视化界面设计、模型训练与视频检测,权重文件提供初始训练与最优模型,说明文档则包含数据集说明和部署教程,资源整体约15.91MB。代码经测试可运行,配套完整数据集,训练时可输出核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果与标签分布图,便于直接用于论文图表和答辩展示。目前已有55人学习下载,适合需要快速搭建项目、节省开发时间的学生与开发者直接使用,也可在此基础上进行二次开发。
1. 牲畜异常行为识别,为什么YOLOv8是更现实的选择
在规模化养殖场景里,牲畜的跛行、打斗、食欲不振、久卧不起等异常行为,往往意味着疾病、发情或应激状态,传统依赖饲养员人工巡检的方式,既依赖经验、又容易漏检,尤其在夜间或大栏位场景下几乎不可持续。很多人会第一时间想到姿态估计或时序行为识别方案,但在实际落地中,这些方案对算力、标注成本、视频帧连续性的要求都远比想象中高,一个几百头的牛舍根本养不起动辄多卡GPU的训练环境。相比之下,基于YOLOv8的目标检测方案,可以在单帧图像上完成牲畜个体的定位与状态分类,标注成本低、部署链路短、推理速度快,这也是《基于YOLOv8的智慧牧场牲畜异常行为识别系统》选择它的根本原因。这套资源不是纸上谈兵的原型,而是包含了完整数据集、训练脚本、推理脚本和可视化界面,几乎从标注格式到最终Web展示一条龙。适合正在做毕设、课设的在校生,也适合想快速验证CV落地路径的工程师。
2. YOLOv8网络结构解析与牲畜数据集的标注适配
2.1 C2f模块到底改了什么,为什么对小目标更友好
YOLOv8的骨干网络延续了CSPNet的设计思路,但把YOLOv5中的C3模块替换成了C2f模块。C2f的核心改动在于将输入特征图分成两条分支,一条走梯度流,另一条经过多个Bottleneck堆叠后再与梯度流拼接。相较于C3,C2f在保持轻量化的同时增加了梯度回传的路径数量,让每个Bottleneck的输出都能直接参与后续特征融合。这个改动对牲畜这类非刚性目标非常关键,因为牛的四肢、羊的头部在图像中往往占比极小,梯度流丰富了,浅层特征中的边缘和纹理信息才能更充分地传到检测头。
从网络结构上看,YOLOv8的Neck部分仍然采用FPN+PAN结构,但PANET的C3层同样替换为C2f。这意味着上采样和下采样路径上的特征融合都在用更多shortcut连接,浅层定位信息和深层语义信息之间的相互补充更充分。实际训练牲畜数据时,最直接的体感是,羊群密集场景下互相遮挡的个体,漏检率比YOLOv5s有明显下降。
官方提供的yolov8n.pt是nano版本,参数量仅3.2M左右,计算量约8.7GFLOPs,在GTX 1660 Ti这类6GB显存的显卡上,batch size设为16甚至32都能跑得动。如果你用的是官方默认的coco预训练权重,它已经具备了通用的特征提取能力,但coco数据集里并没有牲畜异常行为类别,所以迁移学习时建议冻结backbone前10层,只训练head部分,等loss下降到一定程度再解冻全模型微调,这样能避免灾难性遗忘。
2.2 数据集目录结构与YOLO格式的标签文件
这套资源提供的完整数据集遵循YOLO标准目录结构,自定义数据集时最重要的就是保持目录名和标签格式完全一致。一个典型的布局如下:
dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── data.yaml └── classes.txtlabels目录下的每个txt文件与images目录下的jpg文件一一对应,文件名相同、扩展名不同。每行标签的格式为:
class_id x_center y_center width height其中x_center、y_center、width、height都是相对于图像宽高的归一化坐标,取值0到1。例如一张1920x1080的图像中,一头牛的中心点位于(960, 540),框宽为480、高为360,那么对应标签行就是:
0 0.5 0.5 0.25 0.333项目中的data.yaml是训练入口,它定义了路径和类别名,实际项目中重点检查path和names两处是否与本地目录匹配。使用LabelImg或X-AnyLabeling标注后导出为YOLO格式即可,注意标注时框要尽量贴合目标边缘,不要留太多背景,否则训练出来的框会偏大,影响后续IOU计算的准确性。
3. 从零跑通train_mode.py:训练脚本解读与超参数调优
3.1 训练脚本的主流程与关键参数
train_mode.py是这套资源的核心训练入口,封装了YOLOv8的完整训练流程。脚本的核心逻辑可以拆成四步:加载配置、预处理数据、实例化模型、执行训练回调。下面是精简后的代码骨架,去掉了无关UI逻辑,保留关键链路:
import torch import yaml from ultralytics import YOLO def load_config(config_path="data.yaml"): with open(config_path, "r", encoding="utf-8") as f: config = yaml.safe_load(f) return config def train(): config = load_config() # 加载预训练权重,支持 yolov8n.pt / yolov8s.pt / yolo11n.pt model = YOLO("yolov8n.pt") model.train( data="data.yaml", # 数据集配置文件 epochs=100, # 训练轮数 batch=16, # 显存不够调小到8 imgsz=640, # 输入图像尺寸 workers=4, # 数据加载线程数 device=0, # 使用GPU,CPU则设为cpu patience=20, # 早停轮数 lr0=0.01, # 初始学习率 lrf=0.01, # 最终学习率因子 warmup_epochs=3, # 预热轮数 cos_lr=True, # 余弦退火调度 save_period=10, # 每10轮保存一次checkpoint project="runs/train", # 训练日志根目录 name="livestock_exp", # 本次实验名 exist_ok=True, # 允许覆盖同目录结果 ) if __name__ == "__main__": train()这段代码里,imgsz参数决定了网络的输入分辨率,640是默认值。如果牲畜在图像中占比很小,可以尝试提升到960或1280,但显存占用会指数级上升。batch的调法很简单,显存不够就把batch减半,同时把workers减少,避免CPU成为瓶颈。device参数指定训练设备,单卡训练设为0即可。
3.2 学习率策略与早停机制的实际效果
训练过程中的学习率调度对最终收敛效果影响非常大。YOLOv8默认使用SGD优化器配合warmup和cosine退火,warmup_epochs=3的作用是让模型在前3轮以较小的学习率热身,避免前期梯度爆炸。cos_lr=True让学习率按余弦曲线从峰值衰减到lrf × lr0。
一个实用的经验是,当你的数据集只有几百张图时,初始学习率lr0建议从默认的0.01下调到0.005,因为数据量小、模型容易过拟合,过大的学习率会导致loss震荡甚至不收敛。配合早停参数patience=20,模型在验证集上连续20轮没有提升时自动终止训练,既省时间又避免过拟合。
训练过程中,ultralytics会自动在runs/train/livestock_exp目录下输出训练曲线和验证结果。关注两个文件:results.png和confusion_matrix.png。results.png包含训练集和验证集的box_loss、cls_loss、dfl_loss三条曲线,如果三条曲线下降后在某个点开始反弹上升,说明模型开始过拟合,应该减少epochs或增加数据增强。混淆矩阵则能直观看到哪些类别互相误判。如果想实时监控,可以在训练命令中加上verbose=True,终端会打印每一轮的精度指标。
3.3 指标曲线如何解读,评审最看重哪几张图
训练完成后生成的指标曲线图是全项目的核心交付物,也是毕设答辩中最能体现工作量的一组图。下表中总结了这些图的作用与生成位置:
| 图表名称 | 生成位置 | 核心观察点 |
|---|---|---|
| results.png | runs/train/livestock_exp/ | box_loss与cls_loss的收敛趋势 |
| confusion_matrix.png | runs/train/livestock_exp/ | 类别间是否互相误判 |
| F1_curve.png | runs/train/livestock_exp/ | 最佳置信度阈值对应的F1值 |
| PR_curve.png | runs/train/livestock_exp/ | 不同置信度下精确率与召回率的权衡 |
| val_batch*.jpg | runs/train/livestock_exp/ | 验证集上预测框与真实框的对比 |
| labels.jpg | runs/train/livestock_exp/ | 数据集中所有GT框的分布情况 |
F1分数曲线是最关键的,它的横轴是置信度阈值,纵轴是F1值,当曲线达到最高点时所对应的置信度阈值,就是后续推理阶段最优的conf参数。如果F1最大值低于0.7,说明模型在现有数据上欠拟合或标注质量有问题,优先检查标注框是否偏移、类别是否均衡。PR曲线的面积(AP值)越高越好,如果曲线下面积小但曲线形状稳定,往往是数据集中正负样本比例失衡,可以在训练时通过添加fraction参数控制每轮参与训练的样本比例。
4. 推理链路与可视化界面的三层实现
4.1 Detection_video.py的视频推理管线
训练完成后,真正的落地是处理视频流。Detection_video.py把推理和推流分离成了独立的处理管线,从本地上传视频或连接摄像头RTSP流后,逐帧推理并把结果叠加到画面上。核心代码如下:
from ultralytics import YOLO import cv2 model = YOLO("best.pt") # 加载训练好的权重 cap = cv2.VideoCapture("livestock.mp4") fps = cap.get(cv2.CAP_PROP_FPS) width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) writer = cv2.VideoWriter("output.mp4", cv2.VideoWriter_fourcc(*"mp4v"), fps, (width, height)) conf_threshold = 0.55 # 置信度阈值,低于该值的预测框会被忽略 iou_threshold = 0.45 # NMS的IOU阈值,控制重叠框的抑制力度 while cap.isOpened(): ret, frame = cap.read() if not ret: break # stream=True返回生成器,逐帧输出结果 results = model.predict(frame, conf=conf_threshold, iou=iou_threshold, verbose=False) annotated = results[0].plot() writer.write(annotated) cap.release() writer.release()这段代码的关键在results[0].plot()方法,它会在原图上画出所有置信度超过conf_threshold的检测框,并在框上方标注类别名和置信度。conf参数的选择在推理阶段很讲究,在低点时,模型能召回到更多目标,但也会混入大量误检;在高点时会漏检。前面提到用F1_curve的峰值来定,这是最科学的方式,没有之一。
4.2 Visual_interface.py:PySide6桌面界面与YOLOv8解耦
可视化界面是整个系统里最出效果的部分。Visual_interface.py基于PySide6实现,运行时默认加载同目录下的best.pt权重,用户可以从左侧面板选择本地图片或视频,右侧区域实时展示检测结果。界面设计上,除了基础的上传、开始检测、停止检测三个按钮外,还加了一个实时FPS显示标签和类别统计表格,方便在答辩时展示系统的实时响应能力。
界面与推理逻辑之间的通信通过线程池加信号槽机制完成。推理流程如果放在主线程中,会导致UI卡死甚至无响应;而如果直接用Python的多线程,因为GIL的限制,CPU推理时性能也无法完全释放。PySide6的QRunnable配合QThreadPool,可以把推理任务丢到子线程,完成后通过Signal把结果回传UI线程。这个模式是PySide6开发的普遍做法,稍微改一下也可以接入Web端。
4.3 从单张图片到RTSP视频流的切换方式
上面的代码演示了处理本地视频,但要直接接海康或大华的RTSP摄像头,只需要把VideoCapture的入参改为rtsp地址。常见RTSP会话大致格式为rtsp://user:password@192.168.x.x:554/Streaming/Channels/101。需要注意,部分摄像头对RTSP并发连接数有限制,测试时建议把码流类型改为子码流(Channels/102),即使主码流的分辨率更高,网络带宽不够时照样会拖垮推理延迟。
cap = cv2.VideoCapture("rtsp://admin:password@192.168.1.64:554/Streaming/Channels/102") cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 只缓冲最新帧,降低延迟CAP_PROP_BUFFERSIZE设为1是控制延迟的关键参数。OpenCV默认会缓冲几十帧,导致画面延迟越来越大,实时监控场景下这个延迟是致命的。线程池加队列的方式也可以达到同样效果,推理线程从队列取最新帧,丢弃旧帧,代码上稍微复杂一点,但效果相当。
5. 部署踩坑记录与模型轻量化的验证方法
5.1 环境配置最容易翻车的三个点
这套资源在Windows和Linux下都能跑,但环境配置有几个高频坑值得提前避开。第一是PyTorch版本与CUDA版本的匹配问题。Ultralytics官方对CUDA版本没有硬性要求,但PyTorch的安装命令和CUDA版本必须一一对应。一个稳妥的做法是用conda创建全新环境后,先装cudatoolkit,再装torch,不要先装torch再去补CUDA。
第二是GTX 1660 Ti这类Turing架构显卡的兼容性。YOLOv8训练过程中默认会开启AMP混合精度,1660 Ti的Tensor Core性能较弱,个别版本的PyTorch在AMP模式下会报CUDA error: device-side assert triggered,这个报错往往不是显存不够,而是标签ID超出了类别总数。检查data.yaml中的nc参数是否与实际标注的类别数一致即可。第三是workspace等于0导致的推理显存溢出。ultralytics在推理时默认使用workspace=0.5,对于2GB显存的显卡,推理大型视频时同样可能OOM,调小conf和iou不能根治,应该在初始化YOLO后手动设置model.predict(..., workspace=0)强制走fallback路径。
5.2 best.pt与yolo11n.pt的精度与速度权衡
项目资源中同时出现了best.pt和yolo11n.pt,这不是摆放错误,而是两条可选的推理链路。best.pt是训练完的模型,在自建数据集上mAP最高,但由于模型是针对特定场景微调的,泛化到其他牧场环境时效果会缩水。yolo11n.pt是YOLO11系列的最新预训练模型,它的优势在于coco通用检测能力更强,如果你需要在通用水牛、羊、马之外检测猪或其他动物,直接用yolo11n.pt泛化性可能更好,但在本项目数据集上的mAP绝对值大概率不如best.pt。
从实测角度看,两者在GTX 1660 Ti上以640x640输入推理时,单帧耗时都在15到25毫秒之间,差异小于10%。所以如果只是毕设演示,直接用best.pt就够了;如果是落地测试,建议构建一个包含多个牧场的测试集,分别用两个模型跑一遍,以最终F1为准则选型。不要迷信某个模型的指标,一切以目标场景的验证集结果为准。
5.3 损失函数曲线异常时的排查清单
训练到一半发现loss曲线不降或者震荡剧烈,通常有以下几个方向可以排查。第一个方向是数据问题:检查labels目录下有没有空txt文件,空的标注文件会让模型在该图上无监督学习,产生大量背景误检。第二个方向是anchors问题,YOLOv8改成了anchor-free架构,对框尺寸不敏感,但输入分辨率太小的时候,小目标的定位误差会被放大。第三个方向是学习率:lr0过高时,前几个epoch的loss可能出现指数级飙升再回落的奇特曲线,此时不要贸然终止,等warmup结束后观察是否有收敛趋势。
还有一个隐藏很深的坑是数据集的缓存机制。ultralytics在训练时会自动把图像缓存到内存,如果你的数据集路径中有中文或空格,缓存文件的生成可能会失败,导致每个epoch都重新加载数据,训练速度陡降。解决方案是确保data.yaml中的path、train、val路径全部使用英文路径,同时关闭缓存:model.train(..., cache=False)。
最有效的验证方式,是找一小批包含典型异常行为的视频片段,分别用不同的conf阈值跑推理,把结果逐帧拼接成对比视频。毕设答辩时评委很可能追问这一句:你怎么证明你的模型能适应不同光照条件。而拿一批真实夜间场景数据,跑完推理后配上检测框的灵敏度曲线,是比任何口头解释都有力的回答。
本文还有配套的精品资源,点击获取