ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

打架检测数据集与YOLO11三格式训练全解析:从标注到部署

打架检测数据集与YOLO11三格式训练全解析:从标注到部署 简介面向监控场景打架检测项目这份资源提供3000张真实监控视角下的高质量打架图片覆盖街道、酒吧、商店、公交车、监狱及空旷地等多元场景包含两人冲突与多人斗殴情况标签统一为fight类别。数据均经labelimg标注同时给出VOC、COCO、YOLO三种常用格式可直接接入YOLO等算法训练。附赠的YOLO11一键训练脚本还兼顾GPU、CPU及Mac芯片平台并附有博主训练日志供参考。资源包为单个PDF文件容量约5.63MB内有数据集完整介绍及百度网盘获取方式目前已有854人学习下载适合从事安防监控、行为分析及目标检测实战的开发者快速部署使用。1. 为什么打架检测数据集比模型结构更卡脖子做目标检测的都知道用 COCO 预训练权重去微调一个车辆识别模型往往几十个 epoch 就有效果。但把同样的套路搬到打架检测上很多人第一次就翻车了——mAP 低得离谱拿测试视频一跑别说检测打架了两个人推搡都被框成“人”然后丢掉。问题基本不在模型而在数据打架是典型的小样本、强语义、长尾行为检测场景公开数据集少标注成本高背景又极其杂乱教室、走廊、工地、地铁站模型稍微换个环境就失灵。这套“打架检测数据集-3000张图对应VOC/COCO/YOLO三种格式标签支持GPU/CPU/Mac三平台YOLO11一键训练脚本”的方案就是把最浪费时间的两个环节一次性解决了一是数据已经标好并且同时给了三种工业级格式不管你是用 Ultralytics 还是 Detectron2 还是老式 VOC 流程都能直接吃二是配套的训练脚本把环境适配和训练参数收敛到一个命令里GPU 机器、纯 CPU 服务器、Mac 上都跑得起来。适合的人很清楚接安防项目要快速出 demo 的、做智慧校园/工地监控想验证打架识别可行性的、以及刚入门行为检测想省掉数据整理功夫的研究生。2. 3000张图与三种格式先搞懂打架检测在“喂”什么2.1 为什么打架检测不能拿通用检测数据硬训通用目标检测数据集比如 COCO 的 person 类只解决“人在哪里”而打架检测要解决的是“人的交互状态是什么”。这两个任务的难度差了一个量级。COCO 里的人可能是站着的、坐着的、走着的姿态相对独立打架场景里两个人通常是高度重叠、肢体互相遮挡、运动模糊严重而且人体关键点扭曲程度远超日常姿态。用 COCO 预训练权重直接做迁移模型第一轮学到的全是“一个完整的人”一旦两人身体重叠超过 30%检测框就开始互相吞并。所以在自建打架检测数据时标注策略不能只画人框而是要把“正在参与肢体冲突的人”整体圈起来作为一个类通常命名 fight。正样本是成对的、有物理接触并且动作幅度剧烈的人负样本则是并肩走路、拥抱、握手、搀扶这类容易混淆的场景。3000 张图听着不多但如果正负样本比控制在 1:2 左右、背景场景覆盖足够其实已经够训练出一个能出 demo 的模型了。关键不在于张数在于每张图里有没有“难例”。2.2 VOC、COCO、YOLO 三种格式到底差在哪很多新手拿到数据集先问三种格式不是重复了吗其实每种格式背后对应一套工具链你手里的训练脚本是哪个生态的就得喂哪种标签。VOC 是早期最通用的标注格式一个图片对应一个 XML 文件人可读性强自研脚本时最好调试COCO 是 JSON 单文件格式MMDetection、Detectron2 这类框架原生吃它YOLO 是归一化坐标的 txt 格式一行一个框Ultralytics 生态直接读它。三种格式的对应关系可以看这张表格式文件组织标注内容主要消费方VOC每图一个 XML绝对像素坐标、类别名PASCAL VOC 工具链、自研脚本COCO单 JSON 内含全部图绝对像素坐标、类别 ID、areaMMDetection、Detectron2YOLO每图一个 txt归一化中心点宽高Ultralytics YOLO 全系列转换的时候最核心的数学关系只有一组VOC 的 (xmin, ymin, xmax, ymax) 是绝对像素值YOLO 需要的是中心点坐标和宽高除以图片宽高后的比例COCO 则是 xmin, ymin, w, h 的绝对像素值。也就是说 COCO 和 VOC 之间只差一个“宽高换右下角坐标”YOLO 则是多一步归一化。理解了这层关系任何格式互转都不会出错。2.3 拿到数据集先做“数据体检”再开训我拿到任何标注好的数据集第一步不是训练而是跑一个数据体检脚本——统计各类别框数量、框的尺寸分布、图片分辨率分布。这一步能提前暴露绝多大数训练翻车的原因。import os import glob from collections import Counter # 以 YOLO 格式为例做数据体检 label_dir datasets/fight/labels/train img_dir datasets/fight/images/train size_buckets {small: 0, medium: 0, large: 0} class_count Counter() total_boxes 0 for label_file in glob.glob(os.path.join(label_dir, *.txt)): img_file os.path.join(img_dir, os.path.basename(label_file).replace(.txt, .jpg)) if not os.path.exists(img_file): print(f[缺失] 标签存在但图片缺失: {img_file}) continue W, H 1920, 1080 # 建议读取图片头信息获得真实宽高 with open(label_file, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print(f[异常] 格式错误: {label_file} - {line}) continue cls, xc, yc, w, h parts class_count[cls] 1 total_boxes 1 # 按归一化宽高和图片尺寸换算绝对像素面积判断大小框 box_pixels float(w) * W * float(h) * H if box_pixels 32 * 32: size_buckets[small] 1 elif box_pixels 96 * 96: size_buckets[medium] 1 else: size_buckets[large] 1 print(类别统计:, dict(class_count)) print(框尺寸分布:, size_buckets) print(总框数:, total_boxes)这段逻辑不复杂但很多人会跳过。它的价值在于如果打架类只有 800 个框、而负样本类有 4000 个框你训练时就要准备应对类别不平衡如果 small 占比超过一半说明你的很多目标是远处的小人影打架训练时得把 imgsz 调到 960 或者加 P6 检测层否则小目标根本检测不到。体检输出的“标签存在但图片缺失”这类问题会直接影响训练时 mAP 异常低——这个坑我在第 5 章会展开讲。3. 把 VOC/COCO/YOLO 串起来格式互转脚本与边界校验3.1 转换逻辑的三个关键映射做三种格式互转核心要维护好三组映射关系图片文件名是唯一主键类别名与类别 ID 的对应关系必须固定不能 VOC 里叫 fight、COCO 里叫 1、YOLO 里又变成 0坐标系上要严格区分绝对像素和归一化坐标。常见的误用是把 YOLO 的 txt 当成通用检测框格式直接喂给读 VOC 的脚本导致 x_center 被当成 xminw 被当成 xmax。这类问题在日志里表现为 loss 下降但 mAP0因为检测框的坐标语义完全是错的。所以下面的转换脚本里我会在函数名和注释里把坐标系写清楚并加了边界校验不合法就直接打印警告。3.2 一份可复用的 VOC/YOLO/COCO 互转脚本import os import json import glob import xml.etree.ElementTree as ET from collections import defaultdict class FormatConverter: def __init__(self, class_names): # 类别顺序表索引就是 YOLO/COCO 的 cls_idname 就是 VOC 里的标签名 self.class_names class_names self.cls_name_to_id {name: idx for idx, name in enumerate(class_names)} def _parse_voc_xml(self, xml_path): 解析 VOC XML返回图片尺寸和绝对坐标框列表 root ET.parse(xml_path).getroot() size_el root.find(size) W int(size_el.find(width).text) H int(size_el.find(height).text) boxes [] for obj in root.iter(object): name obj.find(name).text if name not in self.cls_name_to_id: print(f[跳过] XML 里出现未定义类别 {name} {xml_path}) continue bnd obj.find(bndbox) xmin float(bnd.find(xmin).text) ymin float(bnd.find(ymin).text) xmax float(bnd.find(xmax).text) ymax float(bnd.find(ymax).text) # 边界收缩防止 xmin/xmax 或 ymin/ymax 写反 xmin, xmax min(xmin, xmax), max(xmin, xmax) ymin, ymax min(ymin, ymax), max(ymax, ymin) boxes.append({name: name, bbox: [xmin, ymin, xmax, ymax]}) return W, H, boxes def voc2yolo(self, voc_dir, yolo_dir): VOC XML 转 YOLO txt 的核心函数 os.makedirs(yolo_dir, exist_okTrue) for xml_path in glob.glob(os.path.join(voc_dir, *.xml)): W, H, boxes self._parse_voc_xml(xml_path) base os.path.basename(xml_path).replace(.xml, ) lines [] for box in boxes: xmin, ymin, xmax, ymax box[bbox] cls_id self.cls_name_to_id[box[name]] # YOLO 用中心点 宽高全部归一化到 0~1 xc (xmin xmax) / 2.0 / W yc (ymin ymax) / 2.0 / H w (xmax - xmin) / W h (ymax - ymin) / H # 越界保护归一化后坐标不在 0~1 的处理掉或裁剪 if xc 0 or yc 0 or xc 1 or yc 1 or w 0 or h 0: print(f[异常] 非法框 {box[bbox]} {base}) continue lines.append(f{cls_id} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}) with open(os.path.join(yolo_dir, base .txt), w) as f: f.write(\n.join(lines)) if not lines: print(f[警告] {base} 转换后无有效框原 XML 可能为空标注) def yolo2coco(self, yolo_dir, img_dir, out_json): YOLO txt 转 COCO jsonCOCO 用绝对像素 x,y,w,h images [] annotations [] img_id 1 ann_id 1 for txt_path in sorted(glob.glob(os.path.join(yolo_dir, *.txt))): base os.path.basename(txt_path).replace(.txt, ) img_file None for ext in [.jpg, .jpeg, .png]: cand os.path.join(img_dir, base ext) if os.path.exists(cand): img_file cand break if img_file is None: print(f[缺失] {base} 找不到对应图片跳过) continue W, H 1920, 1080 images.append({id: img_id, file_name: os.path.basename(img_file), width: W, height: H}) with open(txt_path, r) as f: for line in f: parts line.strip().split() cls_id, xc, yc, w, h map(float, parts) xmin (xc - w / 2) * W ymin (yc - h / 2) * H bw w * W bh h * H annotations.append({ id: ann_id, image_id: img_id, category_id: int(cls_id), bbox: [xmin, ymin, bw, bh], area: bw * bh, iscrowd: 0 }) ann_id 1 img_id 1 categories [{id: i, name: n} for i, n in enumerate(self.class_names)] with open(out_json, w) as f: json.dump({images: images, annotations: annotations, categories: categories}, f) print(f[完成] COCO 标注已写入 {out_json}共 {len(images)} 图 / {len(annotations)} 框) if __name__ __main__: # 类别顺序要与 YOLO11 训练时的 data.yaml 保持一致 converter FormatConverter(class_names[fight]) converter.voc2yolo(datasets/Annotations, datasets/labels) converter.yolo2coco(datasets/labels, datasets/images, datasets/annotations.json)转换脚本里有两个细节值得说。第一个是“类别顺序”YOLO 和 COCO 都是拿数字 ID 做类别索引的一旦顺序写错所有框的类别都会错位而且极难发现。我的习惯是把类别表写成一个独立列表然后让格式转换脚本和后续训练脚本共用同一份配置从源头避免两边不一致。第二个是“越界保护”手工标注时偶尔会出现 xmin 大于 xmax 的情况或者标注框超出了图片边界几条像素直接转换后训练会报错或产生 NaN loss转换时顺手修剪或跳过能省下后面大半排错时间。3.3 转换后的三分钟自检转换完成不代表没问题。我每次跑完转换都会做一个交叉验证随机抽 20 张图把转换后的框可视化画在原图上肉眼确认类别和位置对不对。这种做法比任何自动化校验都先一步发现问题。自动化校验则可以做三件事检查 YOLO txt 的每行是否五个数字且归一化坐标在 0-1 之间检查 COCO JSON 的 image_id 是否都对应真实图片文件检查每个标注框的面积是否大于 0。可视化抽检时最常看到的问题是“框错位了半个人身”——大概率是宽高比换算时把中心点坐标和宽高搞混了。这属于典型的手滑肉眼一看就能定位到具体是哪个函数哪个公式的问题比对着日志猜高效得多。如果你用的是 Jupyter直接 matplotlib 画框即可如果是在服务器上把图存成文件再看也行。4. YOLO11 一键训练脚本三平台环境配置与参数收敛4.1 GPU / CPU / Mac 三平台的环境差异YOLO11 由 ultralytics 这个库承载pip 安装一行能搞定但真正把训练跑起来三台机器的坑完全不一样。GPU 机器最顺前提是 CUDA、cuDNN 和 PyTorch 的版本要匹配常见翻车是装好 torch 后torch.cuda.is_available()返回 False基本是 CUDA 装得不对或者 torch 是 CPU 版。纯 CPU 服务器跑训练没问题只是慢但很多人会忽略torch.get_num_threads()默认值偏低不设置的话 CPU 利用率上不去。Mac 上则是 mps 后端Apple Silicon 的 GPU 能参与训练不过 ultralytics 对 mps 的算子支持是逐步完善的版本太老或太新都可能报算子 not implemented。我的建议是用一段环境自检代码放在训练脚本的前面先自动探测设备再启动训练而不是让用户手动选平台。这也是标题里“一键”的底气所在。import torch def auto_select_device(): if torch.cuda.is_available(): device 0 print(f[设备] GPU: {torch.cuda.get_device_name(0)}) elif torch.backends.mps.is_available(): device mps print([设备] Apple Silicon MPS) else: device cpu print([设备] CPU) return device这段代码按优先级选设备。需要注意一个关键点mps 和 cpu 在 ultralytics 的训练逻辑里都不能沿用 GPU 的 batch size 习惯。MPS 显存占用和 CUDA 计算方式不同batch size 设太大容易在某个 epoch 中途抛出一个晦涩的算子错误CPU 则完全受线程数影响需要在训练脚本里显式设置torch.set_num_threads。我一般建议 GPU 上 batch 设在 16-32CPU 和 MPS 上 4-8并且同时把workers参数调小否则数据加载器会成为真正的瓶颈。4.2 数据集配置与一键训练脚本拆解ultralytics 训练需要先写一个数据集 YAML 文件告诉框架图片和标签在哪、类别有哪些。下面是我基于这套打架检测数据集整理的配置文件# datasets/fight.yaml path: ../datasets/fight # 数据集根目录 train: images/train # 相对 path 的训练图片目录 val: images/val # 相对 path 的验证图片目录 names: 0: fight # 类别索引 0 对应打架YAML 里的 path、train、val 三者拼接出的路径会直接传给 ultralytics 的数据加载器。这里最常见的误用是相对路径没写对尤其当训练脚本和数据集目录不在同一层时path: ../datasets/fight会解析出一个不存在的目录导致启动训练直接报 dataset not found。我的习惯是直接用绝对路径或者用 os.path.abspath 动态拼避免路径依赖。训练脚本本身不长核心调用只有一行from ultralytics import YOLO # 固定类别顺序与刚才的转换脚本保持一致 model YOLO(yolo11n.pt) # 或 yolo11s.pt / yolo11m.pt model.train( datadatasets/fight.yaml, epochs120, imgsz640, batch16, deviceauto_select_device(), patience20, lr00.001, seed42, save_period10, projectruns/fight_det, nameyolo11n_baseline, pretrainedTrue, )这里有几个参数直接影响打架检测的效果得展开说。pretrainedTrue意味着从 COCO 预训练权重启程对打架这种数据量不大的任务基本是必须的随机初始化会让收敛极慢且不稳定。imgsz640是默认分辨率如果你的监控画面里人是小目标比如校园操场全景要提高到 960代价是显存占用大幅上升。patience20是早停耐心值连续 20 个 epoch 验证集 mAP 不涨就提前停省时间但不建议设太小打架检测的指标本身就容易波动。lr00.001是我在这个方向比较稳的初始学习率数据规模小学习率大了很容易直接发散训练日志里 loss 猛涨时先检查这里。4.3 训练时盯着哪几个关键日志训练一轮后日志里最该看的是Box(P)、Box(R)和mAP50这三列。mAP50 是指 IoU 阈值 0.5 下的平均精度均值打架检测这种交互行为场景mAP50 做到 0.75 以上就已经具备实用价值mAP50-95 是更严格的指标会明显低一些不用被它吓到。如果看到 mAP 徘徊在 0.3 以下先不要调模型结构回头检查数据类别数量对不对、标签有没有错位、验证集是不是和训练集分布差异太大。训练结束后会在runs/fight_det/yolo11n_baseline/里产出weights/best.pt和last.pt。best.pt 是验证集上表现最好的权重部署和测试一律用 best.pt不要为了省事用 last.pt——训练后期模型可能过拟合last.pt 的表现往往比 best.pt 差不少。我习惯每次都把 best.pt 单独拷出来重命名加上数据集描述和时间戳毕竟读代码的人不一定记得住这次训练到底用的哪套数据。4.4 用训练好的模型跑一段 RTSP 监控流验证数据集训练出来的模型最终要在视频流上验证不能只看验证集的静态指标。常见做法是用 cv2 拉取监控摄像头的 RTSP 流再丢给模型推理下面是这个方向的常用骨架import cv2 from ultralytics import YOLO model YOLO(runs/fight_det/yolo11n_baseline/weights/best.pt) cap cv2.VideoCapture(rtsp://your_monitor_stream) # 换成实际可用的视频流地址 while cap.isOpened(): ret, frame cap.read() if not ret: break results model.predict(frame, imgsz640, conf0.25, device0) for r in results: boxes r.boxes.xyxy.cpu().numpy() confs r.boxes.conf.cpu().numpy() for box, conf in zip(boxes, confs): x1, y1, x2, y2 map(int, box) label ffight {conf:.2f} cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(frame, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imshow(fight detection, frame) if cv2.waitKey(1) ord(q): break cap.release() cv2.destroyAllWindows()推理时要格外注意conf这个阈值。打架检测场景宁可误报不可漏报conf 设在 0.15-0.25 之间比较合理如果误报太多再往 0.3 以上调。但单帧模型的召回率再高也有限真实场景还要配合时序平滑——这是最后一章要展开讲的进阶内容。5. 打架检测训练避坑5 条血泪经验汇总5.1 标签错位mAP 为 0 但 loss 正常下降现象训练了 50 个 epochmAP 始终是 0loss 却一路下降玄学得像黑匣子。原因标签文件与图片文件没有严格一一对应。数据集里的图片可能经过裁剪或重命名但 XML/txt 里的文件名没同步更新导致模型读到的图片和标签不是同一张图。常见于手工整理数据集时只拷贝了图片忘记拷贝标签或者转换脚本以标签文件名反查图片时找到了另外一张同名图。解决在上面的数据体检脚本基础上加一道强校验——遍历所有图片文件逐个确认存在同名标签文件反过来遍历所有标签文件确认存在同名图片。两边都缺一不可。一旦发现缺失不要手动补直接删除这对孤儿文件换新数据源因为手工补标签容易补错坐标语义。5.2 框坐标越界导致训练直接中断或产生 NaN loss现象训练到某个 epoch 突然报错提示边界框数值非法或者 loss 值变成 nan。原因标注工具生成的框超出了图片宽高边界比如 xmax1921 而图片宽只有 1920。YOLO 格式归一化后百分比可能超过 1.0ultralytics 在训练数据增强阶段对这种框极其敏感。另一个常见来源是格式转换脚本里坐标公式写错导致宽高算成负数越界框得以存活进训练管线。解决在转换脚本里增加归一化坐标的越界检查把越界框修剪到图片边界内而不是直接丢弃——有些框只是超出几个像素丢掉会损失有效标注。修剪逻辑很简单xmin 和 xmax 分别 clamp 到 [0, W]ymin 和 ymax 分别 clamp 到 [0, H]然后重新计算中心点和宽高。这条规则要写进格式转换的公共函数里不能只修一次因为数据会不断更新迭代。5.3 Mac MPS 训练中途报粗粒度的算子错误现象在 MacBook 上启动训练顺利跑了两千多个 iteration 后突然抛出一个 PyTorch 算子 not implemented 的错误训练直接中断。原因MPS 后端对部分算子的支持不完整数据增强里的某些操作尤其和旋转、透视变换相关的在 MPS 上没有实现或实现有 bug。ultralytics 版本更新很快某次升级后原本能跑的脚本也开始报错属于常见情况。解决核心思路是让训练环境的脆弱面最小化。第一固定 ultralytics 版本不要随意升级第二在训练参数里关闭重型数据增强比如把degrees调成 0、perspective调成 0第三如果还是报错退回 CPU 训练Mac 的 CPU 训练速度其实还能接受毕竟打架检测数据集只有 3000 张图多等几个小时换来稳定性值得。我在 Mac 上跑这个数据集通常直接选择 CPU 训练省下的排错时间远大于 GPU 加速带来的收益。5.4 类别不平衡正样本太少导致模型漏检严重现象训练完的模型在测试视频里一个打架行为都检不出来但正常行人倒是框得很准。原因数据集中 fight 类的框数远少于背景或者其他负样本类模型天然偏向多数类把赌注全压在“没有打架”上能获得很高的表面指标。尤其当验证集里打架框占比很低时mAP 会虚高掩盖漏检问题。解决先用 2.3 的体检脚本算出分类别框数。如果 fight 框不足整体 20%做两类操作一是复制正样本图片并在复制时做 mosiac/random_perspective 增强二是调小 loss 里类别惩罚权重对多数类的倾斜。ultralytics 里可以调整cls参数来提高分类损失权重把这个值从默认 0.5 调到 1.0-1.5 之间模型会更卖力去拟合少数类。调参之后一定要单独观察 fight 类的召回率而不仅是整体 mAP。5.5 单帧误检拥抱、握手、搀扶被识别成打架现象模型在测试视频里看到两个人拥抱就报警误报率高到没法上线。原因单张静态图里“打架”和“拥抱/搀扶”在姿态上是高度混淆的。打架有大幅度肢体摆动、头部后仰、身体倾斜但这在某一帧截图上和拥抱区别不大模型根本没有足够信息做判断。这是行为检测的固有难题不是数据量能直接解决的。解决训练集里加入大量高相似度的负样本比如握手、拥抱、拍肩、搀扶把它们单独作为 one more 类标出来让模型学会区分。部署侧则用多帧投票——连续 N 帧里至少 M 帧检出 fight 才触发报警。我一般用 N10、M6即 1 秒内至少 0.6 秒被判定为打架误报能压掉一半以上。这个方案不增加训练复杂度只在推理环节加一个计数逻辑是性价比最高的后处理手段。6. 把模型从“能跑”变成“能上线”时序投票与导出部署训练得到一个 best.pt 只是开始。打架检测这种场景要实际部署至少得做两件进阶事一是给模型加上时序平滑逻辑二是把它导出成部署格式。时序投票的代码不长但逻辑必须想清楚——它维护一个滑动窗口计数器按帧推进只有当窗口内的打架检出帧占比超过阈值时才真正输出报警信号from collections import deque class FightVoteFilter: def __init__(self, window_size10, vote_threshold6): self.window deque(maxlenwindow_size) self.threshold vote_threshold def update(self, is_fight_frame): self.window.append(1 if is_fight_frame else 0) return sum(self.window) self.threshold这个 10 帧滑动窗口对应 1 秒左右的视频长度。window_size 和 vote_threshold 的取值要按实际场景微调如果监控场景是密集人群窗口可以拉长到 15 帧如果要求秒级报警win_size5、threshold3 也够用。我接项目时一般先按上面这组默认值跑再根据客户对误报的容忍度调——安防客户能接受漏报比例低但误报频繁吗通常不能所以宁可窗口大一点、反应慢一秒。导出部署也有讲究。如果你要部署到 GPU 服务器上跑实时推理把 best.pt 导出成 TensorRT 格式会快非常多如果要扔到边缘盒子或没有 PyTorch 的环境ONNX 是通用选择。ultralytics 里一行命令搞定yolo export modelruns/fight_det/yolo11n_baseline/weights/best.pt formatonnx dynamicFalse imgsz640导出 ONNX 时最容易踩的坑是 dynamic 参数——默认固定分辨率会让模型在其他分辨率下推理出错但开 dynamic 又要检查部署框架支不支持动态输入。我的建议是先固定分辨率导出部署时把输入帧 resize 到 640 再送进模型这套流程最稳。我个人的习惯是跑任何行为检测类项目都会留出 20% 的时间单独做数据清洗而非调参——格式转换、标签校验、负样本补充这些环节的边际收益永远比换模型结构大得多。打架检测数据集做到现在这个配合度3000 图 三格式 三平台脚本真正价值在于把重复劳动压缩到了最低省出来的时间值得全砸到场景适配上去。希望组里正在做类似方向的你能靠着这套组合拳少踩几个坑。本文还有配套的精品资源点击获取
返回列表