尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

YOLO11打架检测实战:从标签格式转换到模型部署全流程

发布时间:2026/9/30 1:30:45

资讯中心
01
ARTICLE

YOLO11打架检测实战:从标签格式转换到模型部署全流程

YOLO11打架检测实战:从标签格式转换到模型部署全流程
简介面向监控场景打架检测任务数据集介绍涵盖街道、酒吧、商店、公交车、监狱、空旷地等真实监控场景包含两人打架、多人群殴等典型样本统一标注fight类别并提供VOC、COCO、YOLO三种常见目标检测格式标签可直接用于YOLO等主流算法训练也适合作为监控场景通用打架检测数据的补充。压缩包内为1个PDF文件约5.63MB内容包含数据集基本情况、labelimg标注示意以及百度网盘获取方式方便快速了解数据组织与标注规范。随附YOLO11一键训练脚本支持GPU(GPUs)、CPU、Mac(M芯片)三平台运行避免繁琐环境配置同时提供博主训练结果日志可对比参考损失曲线与精度表现助力调参。已有853人学习浏览对于目标检测学习者及安防项目开发者是快速搭建打架检测模型训练流程的高性价比资料。1. 打架检测为什么这个任务不能拿通用目标检测直接套拿到一个「打架检测数据集-3000张图-带VOC/COCO/YOLO三种格式标签」的项目很多人第一反应是这不就是目标检测里多一个类别吗直接按普通行人检测那套跑不就行了。真跑起来会发现打架检测和常见的行人检测、车辆检测有本质区别——你要检测的不是一个完整清晰的目标而是两个人或一群人肢体互相纠缠、遮挡严重的混乱状态。普通目标检测的锚框、NMS、置信度阈值在这种场景下很容易失灵模型经常把一个打架动作识别成两个人站在一起或者干脆漏掉。这类任务适合谁做适合两类人一类是做安防监控、校园/园区纠纷预警的算法工程师需要快速产出一个能用的打架识别模型另一类是刚接触YOLO系列、想用一套带完整标签的数据集把训练流程走通的学习者。3000张图在目标检测里不算多但有三种格式标签、配跨平台训练脚本意味着你可以跳过最耗时的数据整理环节直接把精力放在模型训练和调参上。这篇文章会从数据格式、格式转换、跨平台训练脚本、参数设置、常见问题五个层面把这个方案讲透。2. 三种格式标签怎么选VOC/COCO/YOLO 的差异与转换2.1 三种标注格式的本质差异XML、JSON、TXT打架检测数据集同时给了VOC、COCO、YOLO三种标签很多人会纠结“到底用哪个”。其实这三种格式描述的是同一个东西——图片里目标的位置和类别——只是存储方式不同。VOC格式每张图对应一个XML文件框的坐标是绝对像素值用xmin/ymin/xmax/ymax四个节点存人类能直接看懂COCO格式把所有标注汇总到一个JSON文件里用[x, y, width, height]表示框还带segmentation、area这类扩展字段YOLO格式则是每张图对应一个TXT文件一行一个目标格式是class_id x_center y_center width height坐标全部归一化到0到1之间。实用角度讲VOC适合人工检查和排查标注错误COCO适合做多类别、带分割的数据集YOLO格式是训练时的“最终形态”。几乎所有的YOLO系列训练脚本包括YOLO11底层都期望吃YOLO格式的标签目录。所以我的习惯是不管拿到的数据是哪一种格式先统一转成YOLO格式再用一套脚本校验最后才进训练。三种格式各存一份不是浪费是给你在“查错”和“训练”之间切换的余地。2.2 VOC 转 YOLO把 XML 坐标算成归一化中心点转换逻辑不复杂但容易写错。VOC里的xmin/ymin/xmax/ymax是像素坐标YOLO需要的是相对于图片宽高的中心点坐标和宽高比例公式是x_center (xmin xmax) / 2 / image_widthy_center (ymin ymax) / 2 / image_heightbox_width (xmax - xmin) / image_widthbox_height (ymax - ymin) / image_height如果只做一步除法忘了除以图片尺寸训练时loss会直接炸掉。下面是我常用的转换脚本核心片段import xml.etree.ElementTree as ET import os def voc2yolo(xml_path, out_txt, class_map): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_map: continue # 不在类别表里的目标直接跳过 box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center ((xmin xmax) / 2) / img_w y_center ((ymin ymax) / 2) / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{class_map[name]} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt, w) as f: f.write(\n.join(lines))注意class_map必须是个显式字典比如{fight: 0}而不是用[fight].index(name)去反查。原因后面避坑章节会说。这个脚本还会忽略不在类别表里的目标——这种做法在高噪声数据集里很有用宁可丢一个标注也别把错误的类别写进标签文件。2.3 COCO 转 YOLO从 JSON 里按 image_id 对齐COCO格式转YOLO要处理两件事一是从images数组里建image_id - 图片文件名、宽高的映射二是把annotations里的bbox字段COCO存的是[x, y, w, h]左上角坐标加宽高转成归一化中心点格式import json def coco2yolo(json_path, out_dir, class_map): with open(json_path) as f: data json.load(f) img_info {img[id]: img for img in data[images]} ann_groups {} for ann in data[annotations]: ann_groups.setdefault(ann[image_id], []).append(ann) for img_id, anns in ann_groups.items(): img img_info[img_id] img_w, img_h img[width], img[height] lines [] for ann in anns: cat_id ann[category_id] cls_id class_map.get(cat_id) # COCO的category_id不是连续的 if cls_id is None: continue x, y, w, h ann[bbox] x_center (x w / 2) / img_w y_center (y h / 2) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w / img_w:.6f} {h / img_h:.6f}) out_path os.path.join(out_dir, img[file_name].rsplit(., 1)[0] .txt) with open(out_path, w) as f: f.write(\n.join(lines))这里最容易被忽略的是category_id往往不连续比如打架类的id可能是3而不是0直接用category_id当类别编号会让标签全部错位。同时注意图片文件名可能带子目录前缀写输出路径时要做一级目录处理。转换完不要急着训练先做一次三分钟的数据体检统计每个TXT文件里有没有空行、坐标值有没有超出0到1范围、类别id是否都在合法区间。用一句grep -E [0-9] (1\.[0-9]|[0-9]\.[0-9]) (1\.[0-9]|[0-9]\.[0-9]) labels/train/*.txt就能把坐标大于1的记录捞出来这类文件后续会直接在训练时报all labels are empty。2.4 数据集划分按场景分层别按文件名随机切3000张图划分train/val看起来是个随机操作但打架检测有它的特殊性。很多打架视频是一段连续帧抽出来的同一段视频的相邻帧画面高度相似。如果随机划分很可能某一段打架序列的画面同时出现在训练集和验证集里val的mAP会虚高部署到真实监控场景立刻现原形。我一般会先看文件名前缀或所在目录按“场景”分组——同一个视频、同一个地点产生的图片归到同一组——再在组级别上做划分。比例按场景数来不按图片数来python -c import os, random files os.listdir(labels/train) # 按前缀分组 groups {} for f in files: prefix f.split(_)[0] # 假设文件名形如 scene01_0001.txt groups.setdefault(prefix, []).append(f) keys list(groups.keys()) random.seed(2024) random.shuffle(keys) split int(len(keys) * 0.8) train_keys, val_keys keys[:split], keys[split:] # 写 train.txt / val.txt 列表文件 省事归省事直接按图片随机切8:2也能跑到90%的mAP但那只是“考试分数”不是“实战能力”。3. YOLO11 一键训练脚本一套代码跑通 GPU、Mac、CPU3.1 环境配置先想清楚ultralytics 包和 torch 版本YOLO11是ultralytics框架在YOLOv8之后的新一代模型训练入口比早期YOLOv5简单很多核心只需要两行from ultralytics import YOLO和model.train(...)。环境配置的常见做法是pip install ultralytics torch torchvisionGPU机器的坑主要在torch和CUDA版本不匹配。稳妥的做法是先装CPU版torch跑通代码再按显卡驱动版本换GPU版。Mac用户装的是苹果的MPS版torch默认pip包在M系列芯片上会自动走MPS后端不需要额外配置。CPU机器最省心但训练速度要做好心理准备——3000张图跑60轮CPU大概要十几个小时。3.2 训练脚本的设备自检与参数自适应所谓“一键训练脚本”核心不是把ultralytics的API包一层而是让脚本自己判断当前机器是什么平台、有多少显存、该用什么batch size这一步做不好“一键”就是个摆设。下面是我整理过的训练脚本骨架import os, sys, yaml, torch from ultralytics import YOLO def pick_device(): if torch.cuda.is_available(): return 0 # 至少一块NVIDIA GPU if hasattr(torch.backends, mps) and torch.backends.mps.is_available(): return mps # Apple Silicon return cpu def auto_batch(device, imgsz640): if device cpu or device mps: return 8 mem torch.cuda.get_device_properties(0).total_memory / 1024**3 return max(4, min(64, int(mem * 4))) # 1G显存约对应batch4 device pick_device() data_yaml { path: /data/fight, # 数据集根目录 train: images/train, # 相对路径 val: images/val, nc: 1, # 类别数打架检测通常单类 names: [fight], } model_path sys.argv[1] if len(sys.argv) 1 else yolo11n.pt model YOLO(model_path) model.train( datadata_yaml, epochs60, imgsz640, batchauto_batch(device), devicedevice, workers4 if device ! cpu else 0, patience15, namefight_yolo11, )这段代码最关键的三个参数是device、batch、workers。device决定跑在哪个后端auto_batch函数在GPU上按显存估算batch1G显存对应batch约48G显存就是32这个经验值比固定写死batch16可靠得多。workers在CPU上必须设成0不然数据加载线程会抢CPU算力训练速度反而更慢。3.3 Mac 上训练的几个细节MPS 后端与算子回退Mac平台用MPS训练YOLO11整体能跑但有几个细节是Windows和Linux用户遇不到的。第一是MPS的内存回收机制不如CUDA积极连续训练几十轮后可能出现“MPS out of memory”这时把batch从8降到4通常能解决。第二是MPS对部分算子的支持不完整出现not implemented for MPS报错时设置环境变量PYTORCH_ENABLE_MPS_FALLBACK1让不支持的算子自动落回CPU执行。export PYTORCH_ENABLE_MPS_FALLBACK1第三是mosaic增强在MPS上偶尔会出问题。ultralytics默认训练最后10轮会自动关闭mosaicclose_mosaic参数这个默认行为在Mac上不要关否则可能遇到训练loss反复横跳的玄学问题。如果你的Mac是M1基础款、内存只有8G我会直接建议用yolo11n这个最小的模型权重把imgsz降到640以下否则一次前向的耗时会让训练周期拉长到无法接受。如果机器不止一块GPUdevice参数可以传0,1ultralytics会自行做数据并行。此时auto_batch算出来的单卡batch应乘以卡数不然多卡效率上不去。要不要上多卡取决于你的单卡显存是否低于6G——低于6G建议直接换个更大的卡或减小模型而不是硬上多卡。4. 从3000张图到可用模型参数、增强与评价指标怎么定4.1 打架场景的参数起点用 640 输入还是 1280 输入打架检测的目标尺度有一个特殊性监控画面里人的高度可能只占图片的10%到30%属于中小目标但两个人打架时肢体动作集中在一个局部区域能提供判别信息的是手部、头部、躯干的相对位置这些细节又需要足够的输入分辨率。所以imgsz的选择要平衡两个方向。我的做法是先用imgsz640跑一版baseline然后用验证集里漏检的样例判断问题出在哪。如果漏检集中在画面远处的小人说明分辨率不够把imgsz提到960或1280如果漏检集中在近处但遮挡严重的画面说明不是分辨率问题而是数据里这种场景本身太少加上数据增强去补。3000张图的规模不建议一上来就用1280训练时间直接翻三倍效果未必能回来。4.2 训练参数配置表与数据增强取舍打架检测不是常规目标检测增强策略要跟着场景改。常规检测里常用的mosaic增强在打架检测中反而要谨慎——mosaic把四张图拼成一张两个打架场景拼在一起会产生大量异常遮挡模型学到的是“混乱打架”的假关联。下面是我在打架数据集上比较稳的参数组合参数推荐值说明epochs60~803000张单类60轮足够收敛patience15验证集连续15轮不涨就停imgsz640起步漏检多再升960注意显存占用batch按显存自适应见上章脚本CPU/Mac固定8mosaic1.0但close_mosaic10保住最后10轮最后阶段关掉稳定收敛fliplr0.5左右翻转对打架动作语义无影响scale0.5模拟不同距离的监控画面hsv_h/s/v0.015/0.4/0.4监控场景光照变化大适度增强scale0.5这个值值得单独说。监控视频里人物尺度变化极大近处的人占半个画面远处的人只有几十个像素。YOLO11有人提到“小目标增强模块”的概念落地到超参数上其实就是提高输入分辨率、降低scale增强的随机下限、或者换带P2小目标检测头的模型变体。对打架检测来说先把scale增强开起来比换模型结构性价比高得多——它直接让模型见过更多不同尺度的人体。4.3 评价指标打架检测不能只看 mAP50常规目标检测看mAP50和mAP50-95打架检测还要额外关注两类指标因为任务目标不是“框得准”而是“别漏报”。打架事件一旦漏掉报警系统形同虚设框偏一点、IoU低一点反而无所谓。所以我会把F1-score和PR曲线当主要指标mAP当辅助参考。from ultralytics import YOLO model YOLO(runs/detect/fight_yolo11/weights/best.pt) metrics model.val(data/data/fight, splitval) print(metrics.box.map) # mAP50-95 print(metrics.box.map50) # mAP50 print(metrics.box.mp, metrics.box.mr) # 精确率和召回率调参时要盯着mp和mr的剪刀差。只跑一轮就发现mp0.95但mr0.4说明模型非常保守宁可不预测也不误报——这在打架检测里是最差的结果。反过来mr很高但mp低说明误报多还可以通过调高conf阈值压下去。遇到前者优先去补数据、降置信度阈值遇到后者先调后处理别急着加数据。5. 避坑排查从标签转换到训练脚本的 5 个常见问题5.1 转换后标签全错位类别编号和顺序对不上现象VOC转YOLO后训练能正常跑loss也在降但验证集mAP几乎为0画出来预测框的类别全是乱标。原因转换脚本里用了[fight].index(name)这种方式去取类别id。XML里name是字符串“fight”列表里恰好在0号位平时没问题一旦数据集里混入其他名字的标注index返回1、2而且你可能根本没注意。解决用显式字典做映射class_map {fight: 0}脚本里遇到不在字典里的name直接跳过。转换完成后跑一遍类别统计cat labels/train/*.txt | awk {print $1} | sort | uniq -c确认只有0这个类别id。5.2 训练时报 “All images not found”现象脚本里的数据路径写对了训练一开始就报错说找不到图片。原因最常见的不是路径错而是图片后缀大小写混用。Windows上导出的图片可能叫XXX.JPGLinux和macOS文件系统大小写敏感glob要精确匹配.jpg才能找到文件。解决训练前统一图片格式find /data/fight -name *.JPG -exec rename s/\.JPG$/.jpg/ {} \;同时检查images/train和labels/train文件名是否一一对应用diff (ls images/train) (ls labels/train)对比就能看出缺哪几张。5.3 图片集里存在无效图片导致训练中断现象训练到某个epoch时突然报ValueError: cannot identify image file。原因数据集中混入了破损的图片或误命名文件。打架检测数据来自不同采集渠道图片在传输过程中损坏很常见。解决训练前用OpenCV或PIL批量检测把打不开的图片剔除或重生成from PIL import Image import os bad [] for f in os.listdir(/data/fight/images/train): try: Image.open(f).load() except Exception: bad.append(f) print(f损坏图片: {len(bad)} 张) # 删除坏图并同步删除对应标签5.4 Mac / CPU 训练速度异常缓慢现象同样60轮别人GPU跑两小时CPU跑了两天还没完Mac上每轮耗时还在逐渐变长。原因CPU训练时workers没设成0数据加载线程和训练线程抢占CPU核心。Mac上则是MPS内存泄漏导致每轮变慢。解决脚本里已处理设备选择但要确认workers4 if device ! cpu else 0这段真的生效了。Mac上降到batch4并设置PYTORCH_ENABLE_MPS_FALLBACK1如果还慢把模型从yolo11n换成更轻的变体或把epochs从60砍到40。5.5 val 指标虚高训练集和验证集数据泄漏现象训练时val的mAP50达到0.95但导出模型跑真实视频时漏检一堆近处打架。原因数据集划分时按图片随机切分同一个打架事件的不同帧同时出现在train和val里。模型等于提前见过“题目”考试成绩自然漂亮。解决按文件名前缀场景ID分组后再划分。如果数据集文件名没有规则就先用聚类或手动按时间戳切片归组。检查方法很简单在val标签里随意挑几类看它的相邻帧序号是否也出现在val里。6. 最后一步用视频推理验证打架模型并压住误报训练完拿到best.pt不要急着部署先用一段真实打架视频跑一次推理重点看两个东西漏报率和误报率。打架检测的漏报比误报可怕得多但误报如果太多监控人员十分钟就麻了。下面的脚本从视频逐帧推理到报警输出都包含核心是加了一个滑动窗口状态机来抑制单帧误报import cv2 from ultralytics import YOLO model YOLO(runs/detect/fight_yolo11/weights/best.pt) cap cv2.VideoCapture(test_fight.mp4) fps cap.get(cv2.CAP_PROP_FPS) conf_thresh 0.45 window_size int(fps * 2) # 2秒窗口 min_hits int(fps * 0.8) # 窗口内至少0.8秒命中 hit_count 0 while cap.isOpened(): ret, frame cap.read() if not ret: break results model.predict(frame, confconf_thresh, iou0.5, verboseFalse) has_fight any(int(r.boxs.cls[i]) 0 and float(r.boxs.conf[i]) conf_thresh for i in range(len(r.boxs))) hit_count hit_count 1 if has_fight else 0 if hit_count min_hits: cv2.putText(frame, FIGHT!, (50, 80), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 3) # 这里接报警逻辑 cv2.imshow(test, frame) if cv2.waitKey(1) 0xFF ord(q): break滑动窗口的意义在于打架动作是持续数秒的事件不会只出现在单帧里。如果单帧置信度超过阈值就报警画面里两人快速擦肩、拥抱、摔倒都会被误报如果连续N帧都稳定命中才报误报率能降到很实用的水平。窗口时长建议按视频场景调整室内监控2秒够用室外人流量大的场景拉到3秒。这就是常说的后处理调参——模型训练完效果还能靠推理侧再优化一层。导出部署时也有讲究。用model.export(formattorchscript)导出免依赖的TorchScript模型在无PyTorch环境的机器上跑CPU推理Mac派生产物用formatcoreml导出配合coremltools可以拿到更低延迟。我习惯每换一个真实场景先跑两分钟demo把conf从0.4往上调找到“误报可接受、漏报还没出现”的那个阈值就固定下来而不是迷信训练时的最优值。这个习惯帮我少翻了很多次车希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。