
简介一套基于YOLOv5的牛只识别检测方案面向智慧养殖、畜牧监控等场景适合需要快速部署目标检测模型的算法工程师与学习者。资源包含完整源码、预训练模型权重、训练及推理脚本并附有loss下降曲线、召回率、精确率、mAP等评估指标曲线可直观了解模型收敛情况。数据侧使用4000余张图片、8000多个牛只标注目标迭代200轮模型拟合效果较好。压缩包共79个文件涵盖Python源码py、配置文件yaml、模型权重pt、评估结果图png/jpg、训练记录txt及Dockerfile等整体约42.58MB目录结构清晰便于对照使用说明快速上手。目前已有271人学习下载适合希望复现牛只检测流程、参考模型训练细节或进行二次开发的用户。1. 牛识别检测为什么选YOLOv5而不是更重的手臂前一阵子接了个奶牛场监控视频的牛头盘点需求要求早晚各统计一次每栏牛的数量高峰时段还要标注出每头牛的位置。最初试过Mask R-CNN单帧推理150ms在4路视频同时分析时CPU直接打满后面换YOLOv5s后单帧降到12ms精确度和召回率都够用。所以这套基于YOLOv5的牛识别检测源码很值得拆一遍里面有4000多张牛图片、8000多个标注目标训练迭代了200轮Loss、Recall、Precision、mAP等评估指标曲线齐全还带模型文件和说明文档。适合正在做深度学习目标检测落地、想找一份能直接跑通并继续改训练流程的项目参考。2. YOLOv5模型结构与训练数据分布2.1 YOLOv5的网络主体与Anchor策略这套源码使用的模型文件是yolov5s.pt在COCO上做过预训练迁移到牛检测场景时收敛速度明显更快。YOLOv5的网络结构分为Backbone、Neck和Head三部分Backbone采用CSPDarknet通过跨阶段局部连接把DenseNet的密集连接拆成两个分支再在CSPBlock里融合相比原版Darknet减少了约一半的计算量Neck采用PANet在FPN基础上加了一条自底向上的路径让高层语义特征和底层空间特征双向流通Head部分则在每层特征图的每个网格上预置3个Anchor输出边界框坐标偏移量、目标置信度和类别概率。Anchor的选择直接影响牛这类高宽比相对固定的目标。YOLOv5的训练过程中会用k-means在数据集上重新聚类Anchor而不是固定使用COCO的默认值。实际跑下来如果牛在画面中大部分是侧面站姿长宽比集中在0.7~1.5之间默认Anchor已经能用如果监控视角是俯拍牛变成俯视椭圆形态就需要在训练前单独聚类。资源的opt.yaml里已经保存了本次训练的全部参数可以直接阅读判断当时是否改过Anchor策略。2.1.1 Backbone与Neck的参数含义训练时图片默认resize到640x640Backbone会输出80x80、40x40、20x20三个尺度的特征图。80x80对应小目标20x20对应大目标。牛在监控画面里通常占30到150像素小目标层和大目标层都需要参与预测。PANet中的shortcut连接会把Backbone第2、3个CSPBlock的输出直接送到Neck这部分在yolov5s.yaml里通过depth_multiple和width_multiple控制。如果希望提升小目标牛的召回可以尝试把imgsz从640提到960但显存占用会翻倍低端显卡容易OOM。2.2 牛数据集的构成与标注规范资源中的训练图片超过4000张标注目标累计超过8000个平均每张图不到2个牛目标数据分布比较分散不是那种背景几乎一样的连续帧。这种分布对训练是友好的能避免模型过拟合到固定机位。通常我拿到这类项目会先看两类文件标注txt与图片名是否一一对应以及是否存在空标注图片。YOLOv5训练时会过滤没有目标的图片但如果空图片比例过高验证集的precision曲线会出现明显抖动。数据集划分常见做法是训练集:验证集9:1测试集直接用验证集替代。因为牛识别的类别单一测试集不参与任何调参这样做不会造成严重的评估偏差。标注格式是YOLO txt格式每行一个目标数据项数量/规格图片总数4000标注目标数8000类别数1类牛标注格式class x_center y_center width height验证集比例约10%图片尺寸原图不等训练时统一resize到640x640完整项目目录大致如下. ├── data │ └── cow.yaml ├── yolov5_code │ ├── detect.py │ ├── train.py │ ├── test.py │ ├── onnx.py │ ├── models/ │ ├── utils/ │ └── weights/ │ └── yolov5s.pt ├── runs │ └── exp_cow │ ├── opt.yaml │ ├── hyp.yaml │ ├── results.txt │ ├── results.png │ ├── precision-recall_curve.png │ ├── labels.png │ ├── labels_correlogram.png │ └── weights/ │ ├── best.pt │ └── last.ptcow.yaml是数据集的入口配置里面指向train和val两个文件夹的图片路径并声明nc: 1和names: [cow]。如果你要复现这套训练需要保证图片和标注txt都放在同一层目录下且txt文件名与图片文件名完全一致这是YOLOv5系列最常见的坑。2.2.1 标注坐标与图片对齐验证标注txt中的x_center y_center width height都是相对图片宽高的归一化值。如果标注文件来自LabelImg坐标单位是像素必须转成归一化格式。检验方法很简单从数据集中随机抽一个标注框把它的x_center * width和y_center * height换算回像素坐标再与原图叠加并保存到本地。如果框明显偏离牛身说明标注工具设置错了。3. 从配置文件到训练命令训练与评估指标曲线3.1 核心配置文件解析训练配置文件是YOLOv5项目里最重要的部分。这个资源中runs/exp_cow/opt.yaml保存了本次训练全部的命令行参数hyp.yaml则保存了数据增强和优化器参数。两个文件配合起来才能完整还原训练过程。3.1.1 hyp.yaml超参数解读hyp.yaml里比较关键的超参数包括学习率、动量、增强开关和各类损失权重。从实际效果看牛识别场景下最影响收敛的是lr0、box和fliplrlr0: 0.01 # 初始学习率SGD常用0.01 lrf: 0.2 # 余弦退火结束后学习率衰减到初始值的0.2 momentum: 0.937 # SGD动量 weight_decay: 0.0005 warmup_epochs: 3.0 # 前3轮学习率从0逐渐升至lr0 box: 0.05 # 边界框回归损失权重 cls: 0.5 # 分类损失权重 hsv_h: 0.015 # HSV色相增强范围 hsv_s: 0.7 # 饱和度增强范围 hsv_v: 0.4 scale: 0.5 # 图片缩放增强 fliplr: 0.5 # 水平翻转概率 mosaic: 1.0 # mosaic增强开关 mixup: 0.0 # mixup增强默认关闭lr00.01是YOLOv5的默认值配合warmup_epochs3能避免前几轮梯度爆炸。box0.05控制框的回归力度如果训练过程中train/box_loss一直不降可以尝试把box调到0.1再跑200轮。fliplr0.5对于牛识别是安全的牛头部方向不影响“牛”这个类别。mosaic1.0对提升小目标检测很有效它把四张图拼在一起等于变相增加了每张训练图中的目标分布。3.1.2 opt.yaml训练参数用下面的命令可以直接查看本次训练实际使用的参数cat runs/exp_cow/opt.yaml输出中会包含epochs200、batch-size16、imgsz640、weightsyolov5s.pt、data../dataset/cow.yaml等。需要特别注意的是bbox_interval字段它决定每个多久记录一次训练批次图。实际调参时我会先把epochs调成50做一个快速实验确认数据集路径和模型文件没问题后再跑完整200轮这样能避免在错误配置上浪费几个小时。opt.yaml还能用于模型复现即使你忘了当时敲了哪些参数只要保留这个文件就能完整恢复训练环境。3.2 启动训练与日志解读3.2.1 训练命令行与参数说明在项目根目录下通过train.py启动训练。假设数据集配置文件在data/cow.yaml模型结构在models/yolov5s.yaml命令行如下python train.py --data data/cow.yaml --cfg models/yolov5s.yaml \ --weights weights/yolov5s.pt --epochs 200 --batch-size 16 \ --imgsz 640 --device 0 --project runs --name exp_cow--data传入数据配置--cfg传入网络结构--weights传入预训练权重。--batch-size根据显存决定16GB显存跑yolov5s时16或32都可以如果显存只有8GB建议用8并用--gradient-accumulation 2维持等效batch。--project runs和--name exp_cow指定输出目录训练完成后所有结果都落在runs/exp_cow/下。--device 0表示用第一张GPU没有GPU时可以改成cpu但200轮会非常慢不建议。3.2.2 从results.txt看评估指标曲线训练过程中写入results.txt每一行代表一个epoch的结果。字段含义如下列名含义epoch训练轮次train/box_loss训练集边界框回归损失train/obj_loss训练集目标置信度损失train/cls_loss训练集分类损失metrics/precision验证集精确度metrics/recall验证集召回率metrics/mAP_0.5IoU阈值为0.5时的平均精度metrics/mAP_0.5:0.95IoU从0.5到0.95取平均的mAPval/box_loss验证集边界框回归损失val/obj_loss验证集目标置信度损失val/cls_loss验证集分类损失用Python可以直接把这些曲线重新画出来方便脱离TensorBoard查看import pandas as pd import matplotlib.pyplot as plt # 读取训练结果列名与YOLOv5的results.txt一致 df pd.read_csv(runs/exp_cow/results.txt, sep\s) plt.figure(figsize(12, 4)) plt.subplot(1, 2, 1) # 画loss下降曲线 plt.plot(df[epoch], df[train/box_loss], labeltrain box_loss) plt.xlabel(Epoch) plt.ylabel(Loss) plt.legend() plt.subplot(1, 2, 2) # 画precision、recall、mAP曲线 plt.plot(df[epoch], df[metrics/precision], labelPrecision) plt.plot(df[epoch], df[metrics/recall], labelRecall) plt.plot(df[epoch], df[metrics/mAP_0.5], labelmAP0.5) plt.xlabel(Epoch) plt.ylabel(Metric) plt.legend() plt.savefig(custom_eval_curves.png)df[train/box_loss]读取的是第一列epoch后面以空格分隔的数据。如果原始results.txt里列名是train/box_loss直接按列名访问即可。代码里使用pandas的sep\s匹配多个连续空格避免因为制表符导致读取失败。从曲线图上能明显看到200轮时训练集loss和验证集mAP都已经趋于平稳说明训练收敛已完成继续增加epoch最多带来零点几个点的提升过拟合风险反倒上升。4. 推理、评估与模型导出detect与test实战4.1 使用detect.py完成单帧与视频推理训练完成后最关心的是模型在真实监控视频上的表现。detect.py支持图片、目录、视频文件和摄像头对于这个牛识别场景最常用的是直接对视频流逐帧检测。4.1.1 推理命令与常用参数python detect.py --weights runs/exp_cow/weights/best.pt \ --source test_video.mp4 --img 640 --conf-thres 0.25 \ --iou-thres 0.45 --save-txt --save-conf--source test_video.mp4指定输入视频文件如果要跑摄像头改成--source 0。--conf-thres 0.25表示只保留置信度高于0.25的框--iou-thres 0.45是NMS的IoU阈值用于抑制同一目标的重复框。--save-txt会输出每帧的检测结果txt--save-conf则会在txt里追加置信度数值。最终结果保存在runs/detect/exp/下。如果是实时视频分析建议把输入源改成RTSP地址同时用VideoStream类单独起读取线程避免解码阻塞推理线程。4.1.2 推理输出与置信度选择检测txt里每行格式为class x_center y_center width height conf这里的坐标同样是归一化值。如果你要统计每栏奶牛数量可以直接读取txt按北类ID做计数。模型文件best.pt的置信度分布一般比较集中高置信度框集中在0.7~0.95之间低置信度框大多是误检。此时我会把--conf-thres从0.25调到0.3能显著降低栏杆阴影造成的假阳性。如果你发现漏检数量偏高则把阈值降到0.15。具体阈值可以结合precision-recall_curve.png来定曲线越靠近右上角说明同时保持高精确度和高召回率的区间越宽。4.2 使用test.py评估mAP与PR曲线detect.py只能输出预测结果如果要做量化评估需要使用test.py。这部分的目的是重新计算验证集上的mAP并生成新的PR曲线和标签分布图。4.2.1 评估命令与参数python test.py --data data/cow.yaml \ --weights runs/exp_cow/weights/best.pt --img 640 \ --conf-thres 0.001 --iou-thres 0.6 --task val--conf-thres需要专门设成0.001这样所有低置信度框都会被保留画出的PR曲线才是完整的。如果设置成0.25PR曲线只会从0.25置信度之后开始无法看到模型在低置信度区间的召回率表现。--iou-thres 0.6是NMS阈值通常比训练时高一些避免把过多重叠的预测框合并掉。--task val显式使用验证集。评估过程会在runs/exp_cow/下重新生成precision-recall_curve.png、labels.png和labels_correlogram.png。4.2.2 从指标曲线判断模型状态评估指标里最值得看的是mAP和PR曲线包络面积。在牛识别这种单类检测任务中我一般会参考下面这个经验表来调整训练策略指标理想范围调整方向mAP0.50.9增加训练数据或提高epochPrecision0.85提高conf-thres或去背景误检Recall0.9降低conf-thres、增加正样本mAP0.5:0.95与mAP0.5差距小改进anchor或提升imgszlabels_correlogram.png非常直观能看出标注框中心点分布和宽高比。牛在监控画面里基本固定在中部所以中心点分布会集中在中间区域宽高比则集中在0.5到2之间。如果看到明显离群点比如中心点在角落、宽高比大于5那么这些图片的标注大概率有问题。项目自带的test_batch0_gt.jpg和train_batch0_pred.jpg分别展示了训练数据的增强效果和测试批次预测结果可以用来排查数据增强是否转换过度以及模型是否漏掉了密集牛栏里体型较小的牛。5. 牛识别落地中的三个实用技巧5.1 用albumentations扩展牛目标的小样本增强如果要把这套模型迁移到自己的农场画面而你的数据不到1000张建议在原来的hyp.yaml基础上再叠加albumentations增强import albumentations as A # 给YOLOv5训练流程外挂一层光照与天气增强 aug A.Compose([ A.RandomBrightnessContrast(p0.5), A.HueSaturationValue(p0.3), A.RandomRain(p0.05), ])配合YOLOv5自带的mosaic一起使用能有效模拟清晨逆光和雨雾天气减少模型对新环境的过拟合。5.2 mAP偏低的排查路径先看labels.png里的标注框是否出现过宽或过窄的目标再看test_batch0_pred.jpg中漏检目标是不是因为遮挡或目标太小。如果小目标漏检把imgsz从640提升到960如果背景复杂误检多在数据集中补充纯背景负样本是更直接的办法。5.3 把PyTorch模型转换为ONNX用于边缘设备python onnx.py --weights runs/exp_cow/weights/best.pt \ --dynamic --img-size 640 640转换后得到best.onnx用onnxruntime加载并推理时输入张量维度是(N, 3, 640, 640)。--dynamic启用动态batch维度方便同时处理多路视频流在Jetson或嵌入式设备上如果不依赖batch推理去掉--dynamic能减少后处理耗时。转换完成后用checker检查输出形状确保它和YOLOv5源码中utils/dataloaders.py里的后处理逻辑保持一致。本文还有配套的精品资源点击获取