
简介本资源为商店偷窃行为识别数据集面向计算机视觉方向的学习者、算法工程师及安防场景研发人员用于训练与评估视频监控下的异常行为检测模型解决偷窃行为自动识别与预警问题。数据采用COCO格式对8395张原始图片完成标注覆盖真实门店监控画面中的可疑动作可直接接入主流目标检测与行为识别框架进行训练。压缩包共2000个文件以1995张jpg图像为主体另含3个json标注文件与2个txt说明文件整体约455.58MB目录组织清晰便于按类别划分训练集与验证集。据描述基于该数据训练的平均准确率可达98.6%已有545人学习下载适合需要快速验证模型效果或开展安防课题研究的中高级开发者参考使用。1. 商店偷窃行为识别数据集8395 张 COCO 标注图能撑起什么先给结论如果你手上有一个 8395 张原始图片、按 COCO 格式标注、宣称平均准确率 98.6% 的商店偷窃行为识别数据集它最现实的用途不是直接上线抓人而是把「货架前的人到底在干什么」这件事拆成可训练、可复现、可验证的检测任务。商店偷窃识别本质上是行为识别的一个窄分支难点不在模型结构而在数据正样本稀少、遮挡严重、动作边界模糊、正常拿取和藏匿之间只差一个手部轨迹。COCO 格式的价值在于它把目标框、类别、图像元信息统一成一份 JSON让你能直接接进 YOLO、Detectron2、MMDetection 这类主流框架而不是先花两周写解析脚本。8395 张这个量级说大不大说小也不小。它足够训练一个中等规模的目标检测器但不足以覆盖所有门店布局、光照和人群密度。98.6% 这个数字要拆开看它大概率是在特定测试集上的平均精度不是真实门店的泛化精度。谁适合用做零售安防的算法工程师、想入门行为识别的高年级学生、以及需要快速验证「货架场景 COCO 标注」这条链路的产品团队。下面我把从数据检查到训练、再到避坑的完整路径讲清楚能抄的代码和参数都给你。2. 把 COCO 标注吃透从 JSON 结构到训练集划分2.1 COCO 格式到底存了什么为什么它比 VOC 更适合行为识别COCO 的核心是一份 JSON里面通常有images、annotations、categories三个主键。images记录每张图的id、file_name、width、heightannotations记录每个框的image_id、category_id、bbox格式是[x, y, width, height]注意不是x1y1x2y2、area、iscrowdcategories把类别 id 映射到名称。行为识别数据集里类别往往不是「人」和「商品」而是「正常拿取」「藏匿」「未结账离开」这类动作标签框可能画在人体上也可能画在手部或商品上。为什么不用 VOCVOC 的 XML 每张图一个文件类别和框分散做多标签和拥挤场景统计很麻烦。COCO 一份 JSON 就能统计全量分布而且iscrowd字段能标记密集人群这对商店场景很关键——货架前经常几个人重叠VOC 没有统一处理方式。常见做法是先确认bbox格式再统计每个类别的框数量最后按image_id做分层划分避免某个类别在验证集里几乎消失。import json from collections import Counter with open(annotations/instances_train.json, r, encodingutf-8) as f: coco json.load(f) # 统计类别分布 cat_counter Counter(ann[category_id] for ann in coco[annotations]) cat_map {c[id]: c[name] for c in coco[categories]} for cid, cnt in cat_counter.most_common(): print(f{cat_map[cid]}: {cnt} boxes) # 检查 bbox 是否越界 bad 0 img_map {img[id]: img for img in coco[images]} for ann in coco[annotations]: img img_map[ann[image_id]] x, y, w, h ann[bbox] if x 0 or y 0 or x w img[width] or y h img[height]: bad 1 print(越界框数量:, bad)这段代码先跑类别分布再查越界框。参数上category_id必须和categories里的id一致否则训练时类别会错位。bbox越界在行为数据集里很常见尤其是手部框贴着图像边缘越界框不处理会导致训练时坐标回归异常。如果越界比例超过 1%建议直接裁掉或修正不要硬训。2.2 8395 张图怎么划分才不翻车分层抽样与防泄漏8395 张图如果随机按 8:1:1 划分很容易出现某个行为类别在验证集里只有个位数样本指标波动极大。更稳的做法是按类别做分层抽样同时保证同一段视频抽出的帧不要同时出现在训练和验证集——这是行为识别最隐蔽的泄漏。商店偷窃数据往往来自连续监控相邻帧高度相似随机划分会让验证精度虚高上线就翻车。import random from collections import defaultdict random.seed(42) # 假设每张图有一个主类别取该图第一个标注的 category_id img_cat defaultdict(list) for ann in coco[annotations]: img_cat[ann[image_id]].append(ann[category_id]) # 按主类别分组 groups defaultdict(list) for img_id, cats in img_cat.items(): main_cat Counter(cats).most_common(1)[0][0] groups[main_cat].append(img_id) train, val, test [], [], [] for cat, ids in groups.items(): random.shuffle(ids) n len(ids) n_train int(n * 0.8) n_val int(n * 0.1) train ids[:n_train] val ids[n_train:n_train n_val] test ids[n_train n_val:] print(len(train), len(val), len(test))这里用random.seed(42)保证可复现按主类别分层后 8:1:1 切分。关键参数是main_cat的取法如果一张图有多个类别取出现次数最多的那个作为主类别避免同一张图被分到多个集合。实际项目中如果数据带有视频来源字段应该先按视频 id 分组再切分而不是按图片。没有视频字段时至少检查文件名的连续性把相邻编号的图放在同一集合。2.3 用 pycocotools 做一次完整性体检在训练之前用官方pycocotools跑一遍COCO()加载和loadAnns能提前暴露 JSON 结构错误。很多自制数据集在categories里重复 id或者annotations引用了不存在的image_id直接训练会报一些很难懂的索引错误。pip install pycocotoolsfrom pycocotools.coco import COCO coco COCO(annotations/instances_train.json) img_ids coco.getImgIds() print(图片数:, len(img_ids)) ann_ids coco.getAnnIds(imgIdsimg_ids) print(标注数:, len(ann_ids)) # 检查每个类别是否有标注 for cat in coco.loadCats(coco.getCatIds()): ids coco.getAnnIds(catIds[cat[id]]) print(cat[name], len(ids))如果某个类别标注数为 0说明这个类别在训练集里没有样本要么补数据要么从类别列表里去掉。getAnnIds返回的是标注 id 列表不是框坐标别混淆。这一步跑通后面接 YOLO 或 MMDetection 基本不会在数据格式上卡住。3. 训练链路从 COCO 到 YOLOv8 与 MMDetection 的落地参数3.1 用 YOLOv8 跑通最小训练转换脚本与三个必调参数YOLOv8 原生支持 COCO 格式但要求目录结构是images/train、labels/train标签是每张图一个.txt每行class_id x_center y_center width height全部归一化到 0-1。所以第一步是把 COCO JSON 转成 YOLO txt。转换时注意bbox是左上角加宽高要转成中心点坐标。import json, os def coco2yolo(json_path, out_dir, img_dir): os.makedirs(out_dir, exist_okTrue) with open(json_path, r, encodingutf-8) as f: coco json.load(f) img_map {img[id]: img for img in coco[images]} cat_ids sorted(c[id] for c in coco[categories]) cat2idx {cid: i for i, cid in enumerate(cat_ids)} per_img {} for ann in coco[annotations]: img img_map[ann[image_id]] x, y, w, h ann[bbox] dw, dh img[width], img[height] cx (x w / 2) / dw cy (y h / 2) / dh nw, nh w / dw, h / dh per_img.setdefault(ann[image_id], []).append( f{cat2idx[ann[category_id]]} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f} ) for img_id, lines in per_img.items(): name os.path.splitext(img_map[img_id][file_name])[0] .txt with open(os.path.join(out_dir, name), w) as f: f.write(\n.join(lines)) coco2yolo(annotations/instances_train.json, labels/train, images/train) coco2yolo(annotations/instances_val.json, labels/val, images/val)转换后写一份data.yaml指定train、val、nc、names。训练命令里三个参数最影响结果imgsz建议 640行为识别里手部动作小再低会丢细节batch按显存给8GB 卡用 8 到 16epochs先跑 50 看曲线别一上来 300。学习率用默认0.01起步如果 loss 震荡就降到0.001。yolo detect train datadata.yaml modelyolov8s.pt imgsz640 batch16 epochs50 lr00.01yolov8s是速度和精度的折中商店场景如果部署在边缘设备可以换yolov8n但小目标召回会掉。训练完看results.csv里的mAP50-95不要只看mAP50后者在行为识别里容易虚高。3.2 MMDetection 路线配置文件改哪几行评估用 COCO 指标如果团队已经在用 MMDetection直接吃 COCO JSON 更省事。以 Faster R-CNN 为例配置文件里需要改metainfo的classes、data_root、ann_file、img_prefix以及num_classes。MMDetection 的评估默认走 COCO 指标bbox_mAP就是mAP50-95和论文对齐。# 在 config 中覆盖 metainfo dict(classes(normal, conceal, leave_without_pay)) data_root data/shop_theft/ train_dataloader dict( datasetdict( data_rootdata_root, ann_fileannotations/instances_train.json, data_prefixdict(imgimages/train/), metainfometainfo, ) ) val_dataloader dict( datasetdict( data_rootdata_root, ann_fileannotations/instances_val.json, data_prefixdict(imgimages/val/), metainfometainfo, ) ) model dict(roi_headdict(bbox_headdict(num_classes3)))num_classes必须和classes长度一致否则分类头维度对不上。训练时lr用0.02配 8 卡单卡按比例缩。评估阶段用tools/test.py加--eval bbox输出的coco/bbox_mAP才是可比较的指标。如果验证集里某个类别样本少于 20 个这个类别的 AP 波动会很大别拿它当唯一判断依据。3.3 98.6% 准确率怎么复现指标口径与验证集陷阱标题里的 98.6% 平均准确率先要问清楚是accuracy还是mAP是在多少张图上测的类别是否平衡。行为识别里如果负样本正常行为占 90%模型全预测正常也能到 90% 准确率这种数字没有意义。复现时建议同时看三个数mAP50-95、每个类别的recall、以及混淆矩阵里「藏匿」被误判成「正常拿取」的比例。from sklearn.metrics import confusion_matrix, classification_report # 假设 y_true, y_pred 是逐框的类别标签 print(classification_report(y_true, y_pred, digits4)) print(confusion_matrix(y_true, y_pred))如果「藏匿」的召回低于 0.8说明模型漏检严重在安防场景里漏检比误报更致命。这时候优先补藏匿动作的样本或者调低置信度阈值到 0.25 再试。98.6% 如果是mAP50那mAP50-95可能只有 70% 左右上线前一定用后者做决策。4. 避坑与排查商店偷窃数据集最常见的 5 个翻车点4.1 现象训练 loss 正常下降验证 mAP 始终为 0原因通常是类别 id 不连续或data.yaml里的names顺序和转换脚本里的cat2idx不一致。COCO 的category_id可能是 1、3、7 这种跳号YOLO 要求从 0 连续编号。解决转换时用sorted后重新映射训练前打印names和标签文件第一行核对。4.2 现象模型把「正常拿取」大量判成「藏匿」原因是两类动作的视觉差异太小框的位置高度重叠模型学到的是「人在货架前」这个共同特征。解决在标注层面区分手部框和人体框训练时加一个手部关键点分支或者把「藏匿」定义为「商品框消失且手部进入口袋/包」的时序事件而不是单帧分类。单帧模型很难区分这是血泪经验。4.3 现象验证集精度很高换一个门店就崩原因是数据泄漏或场景过拟合。8395 张图如果来自同一两个摄像头模型记住了背景货架纹理。解决划分时按摄像头或时间段分组训练时加随机裁剪、色彩抖动、马赛克增强。测试时至少留一个完全没见过的门店片段。4.4 现象小目标手部、商品召回极低原因imgsz640下手部框可能只有 20 像素下采样后特征消失。解决提高输入到 960 或 1280或者在数据加载时对小框做复制粘贴增强。YOLOv8 的copy_paste增强对这类场景有效但要注意别把框贴到不合理的位置。4.5 现象推理速度达不到实时原因行为识别如果用了时序模型如 SlowFast单帧检测加时序融合很容易超过 100ms。解决商店场景通常不需要逐帧判断可以每 5 帧抽一帧做检测再用轻量跟踪如 ByteTrack串起来把「藏匿」定义为跟踪轨迹上的商品消失事件。这样既省算力又比单帧分类稳。5. 进阶技巧用跟踪把单帧检测串成行为事件单帧检测器再准也只能回答「这一帧里有没有可疑框」回答不了「这个人是不是把东西藏起来了」。我一般会在检测之后接一个轻量跟踪把同一人的框串成轨迹再在轨迹上判断商品框的消失。ByteTrack 是性价比很高的选择不需要额外训练直接吃 YOLO 的检测结果。from ultralytics import YOLO import numpy as np model YOLO(runs/detect/train/weights/best.pt) results model.track(sourcestore_clip.mp4, trackerbytetrack.yaml, conf0.3, iou0.5) # 简化逻辑统计每个 track_id 的商品框数量变化 track_history {} for r in results: for box in r.boxes: tid int(box.id) if box.id is not None else -1 cls int(box.cls) track_history.setdefault(tid, []).append(cls) for tid, seq in track_history.items(): if seq.count(1) 0 and seq[-1] ! 1: # 1 代表商品 print(ftrack {tid} 商品消失触发复核)这段代码里conf0.3比训练时的默认阈值低是为了召回更多可疑框后面靠跟踪和事件逻辑过滤误报。bytetrack.yaml是 Ultralytics 内置的跟踪配置不用改。track_history记录每个 id 的类别序列如果商品类别在轨迹末尾消失就标记为待复核事件。实际部署时还要加一个时间窗比如 3 秒内商品消失且人离开货架区域才推给人工。验证这套逻辑是否有效不能只看检测 mAP要看事件级的指标在标注了「藏匿事件」的测试片段上算事件召回和误报率。我习惯用 20 段短视频做回归测试每段 30 秒人工标好事件起止时间然后跑跟踪逻辑对比。如果事件召回低于 0.85先回去查检测漏框而不是调跟踪参数。最后说个习惯每次拿到一个新数据集先花半天做数据体检别急着开训。8395 张图里如果有 5% 的框是错的训出来的模型就会带着这些错误上线。我见过太多团队在 98.6% 的指标上兴奋结果门店实测一塌糊涂。把划分、增强、事件逻辑这三件事做扎实比换更大的模型有用。希望帮到你。本文还有配套的精品资源点击获取