新闻详情

新闻详情

首页 / 资讯中心 / 详情

ByteTrack训练自己的数据集:VOC转COCO与YOLOX实时跟踪

发布时间:2026/10/1 17:44:11来源:尧图网络
ByteTrack训练自己的数据集:VOC转COCO与YOLOX实时跟踪
简介面向目标检测与多目标跟踪开发者的ByteTrack实战教程重点解决从自定义VOC格式数据集准备、模型训练到摄像头实时检测跟踪的完整流程。资源共250个文件压缩包仅1.61MB以145个Python脚本和58个pyc编译文件为主并包含14个Markdown教程文档、C头文件与源码、配置文件及Dockerfile便于代码阅读和环境复现。已有406人学习下载适合具有一定深度学习基础、希望系统上手多目标跟踪的开发者。教程详细拆解了VOC数据集的目录结构JPEGImages、Annotations、ImageSets与标注规范讲解训练环境搭建、检测模型选择、损失函数与优化器配置并延伸到摄像头视频流实时推理与跟踪性能评估内置C实现便于从Python原型转向工程部署同时涵盖数据集划分、预训练权重加载和推理速度优化等关键环节是一份兼顾原理与实践的完整资源。1. ByteTrack 训练自己的数据集为什么我从 DeepSORT 换过来去年我接了一个园区监控的多目标跟踪需求行人一遮挡原来的 DeepSORT 就疯狂改 ID跟踪框老是乱跳。换成 ByteTrack 之后最直观的变化是目标从遮挡里出来后ID 基本还能接回来。ByteTrack 是一个以检测为中心的多目标跟踪框架靠两段式关联把高置信度和低置信度检测框分开匹配不需要额外训练 ReID 模型计算开销也比 DeepSORT 小一截。这套教程资料把最关键的三件事讲全了VOC 数据集怎么转格式喂进去、YOLOX 底座怎么训练、训练完怎么接摄像头实时跟踪。适合已经会给 YOLO 系列准备数据集、但想把“检测”升级成“检测加跟踪”的开发者新手能照着走熟手也能直接抄参数。2. ByteTrack 的两次关联与代码结构BYTETracker.cpp 里到底发生了什么2.1 两次关联的核心思想高置信度先匹配低置信度做补救ByteTrack 之所以叫 Byte是因为它把检测框按置信度分成了“高”和“低”两档分别处理。第一次关联只用高置信度检测框和已有轨迹做 IoU 匹配第二次关联再用低置信度检测框去捞那些第一次没匹配上的轨迹。这个设计解决了一个很实际的问题目标被遮挡时检测器的置信度会掉下来但检测框的位置往往还是准的。如果直接把这些低分框丢掉跟踪就断了如果全拿来匹配又会引入大量误检。ByteTrack 的处理方式是“先紧后松”高分的先锁定低分的做补救匹配不上的轨迹再保留一段时间给它“缓死”的机会。这里的关键是它不用外观特征只看位置和 IoU。第一次关联时卡尔曼滤波预测出轨迹在当前帧的位置和检测框计算 IoU代价矩阵交给线性分配求解器。因为相邻帧目标运动幅度有限位置关联在大多数场景下已经足够省掉了 ReID 网络的前向推理帧率自然就上去了。我在实际项目里的体感是行人密集、互相遮挡的场景下ByteTrack 的 ID Switch 数量明显比 DeepSORT 少而且不需要调一堆特征提取的阈值。2.2 解压 ByteTrack.zip 后的文件清单每个 cpp 的职责边界解压这份资料后核心源码文件不算多我先按职责拆一遍方便你后面定位问题。文件职责BYTETracker.cpp跟踪器主逻辑包含第一次关联、第二次关联、轨迹状态管理bytetrack.cpp示例入口/演示程序负责读取视频流、初始化跟踪器、串联检测与跟踪lapjv.cppLAPJV 线性分配求解器用于计算最优匹配utils.cpp工具函数包含检测框转换、可视化绘制、文件读取等辅助逻辑cocoeval.cppCOCO 格式的评估模块用于计算 mAP 和跟踪指标setup.cfgPython 包元数据和编译配置C 扩展模块的构建入口BYTETracker.cpp 是整套代码的“大脑”它维护着所有轨迹的状态已激活、待确认、丢失。丢失轨迹会放进 track_buffer超过一定帧数才彻底删除。这个 buffer 长度直接影响遮挡后 ID 能不能接回来我一般习惯设 30 到 60 帧场景里遮挡频繁就设大一点。lapjv.cpp 负责的 LAPJV 算法平时不用深究但要明白它比普通匈牙利算法快不少。用 scipy 的 linear_sum_assignment 也能做同样的匹配但逐帧跑时 CPU 开销大换成 LAPJV 后单帧分配耗时能降到毫秒级摄像头实时场景下这个差距很关键。2.3 和 DeepSORT 的关键差异少一套 ReID 反而更稳很多人以为 ByteTrack 是 DeepSORT 的升级版其实思路完全不同。DeepSORT 依赖 ReID 网络提取外观特征再和运动特征融合匹配ByteTrack 直接把外观特征整个砍掉只靠检测框的置信度分层和位置关系。对比维度DeepSORTByteTrack外观特征需要额外训练 ReID不需要低置信度框基本丢弃第二次关联中利用匹配策略一次关联全部轨迹两次关联置信度分层计算开销特征提取成本高IoU 加卡尔曼开销小遮挡恢复依赖外观特征依赖 track_buffer 和低分框补救这个设计带来的直接好处是你不用再为 ReID 准备一套行人重识别数据集训练链路短了一大截。但也要注意一个常见误用ByteTrack 本身不需要训练需要训练的是底层的检测器。如果你拿一个没训练好的 YOLOX 权重直接跑 demo跟踪效果会非常差因为低分框里全是误检第二次关联反而把噪声也捞回来了。3. 把 VOC 数据集喂给 ByteTrack转换脚本与三个检查点3.1 VOC 标准结构和 YOLOX 需要的格式差异ByteTrack 官方仓库配套的检测器是 YOLOX模型训练阶段用的是 COCO JSON 或者 VOC 原生目录。如果你手上的数据是 Pascal VOC 格式目录结构通常是这样的VOCdevkit/ VOC2007/ JPEGImages/ Annotations/ ImageSets/ Main/ train.txt val.txtJPEGImages 放原始图片Annotations 放同名 XMLImageSets/Main 里是参与训练的图片名列表。问题在于YOLOX 的 COCO 数据加载器要求的是train.json这种统一标注文件而且坐标格式从 VOC 的xmin, ymin, xmax, ymax变成了 COCO 的x, y, width, height。我不会去改 YOLOX 的 dataset 代码直接写一个转换脚本把 VOC XML 转成 COCO JSON这样训练配置里只需要改两个路径参数最省事。3.2 动手写 voc_to_coco.pyXML 转 JSON 的完整代码转换逻辑不复杂核心是解析 XML 里的 object 节点重新组织成 COCO 的 images、annotations、categories 三段结构。# voc_to_coco.py import xml.etree.ElementTree as ET import os import json def parse_xml(xml_path, classes): tree ET.parse(xml_path) root tree.getroot() size root.find(size) width int(size.find(width).text) height int(size.find(height).text) objs [] for obj in root.findall(object): name obj.find(name).text if name not in classes: 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) w xmax - xmin h ymax - ymin if w 0 or h 0: continue objs.append({ category: name, bbox: [xmin, ymin, w, h] }) return objs, width, height def convert_voc_to_coco(annot_dir, image_dir, image_set, classes, output_json): with open(image_set, r) as f: img_ids [line.strip() for line in f if line.strip()] images [] annotations [] categories [{id: i 1, name: n} for i, n in enumerate(classes)] ann_id 1 for img_id in img_ids: xml_file os.path.join(annot_dir, img_id .xml) if not os.path.exists(xml_file): continue objs, width, height parse_xml(xml_file, classes) images.append({ id: len(images), file_name: img_id .jpg, width: width, height: height }) for obj in objs: annotations.append({ id: ann_id, image_id: len(images) - 1, category_id: classes.index(obj[category]) 1, bbox: obj[bbox], area: obj[bbox][2] * obj[bbox][3], iscrowd: 0 }) ann_id 1 coco_data { images: images, annotations: annotations, categories: categories } with open(output_json, w) as f: json.dump(coco_data, f, indent2) if __name__ __main__: classes [person, car] convert_voc_to_coco( annot_dirVOCdevkit/VOC2007/Annotations, image_dirVOCdevkit/VOC2007/JPEGImages, image_setVOCdevkit/VOC2007/ImageSets/Main/train.txt, output_jsontrain.json ) convert_voc_to_coco( annot_dirVOCdevkit/VOC2007/Annotations, image_dirVOCdevkit/VOC2007/JPEGImages, image_setVOCdevkit/VOC2007/ImageSets/Main/val.txt, output_jsonval.json )这段脚本有几个地方需要按你的实际情况改classes列表必须和 VOC 标注里的类别名完全一致包括大小写img_id .jpg写死了图片后缀如果数据集里有 PNG 图片建议用 glob 在 JPEGImages 目录里匹配实际文件名。脚本会跳过宽高小于等于 0 的非法框这个过滤不能省训练时遇到这类标注会直接报错。3.3 转换前必查的三个检查点命名配对、类别名、边界坐标第一个检查点是图片名和 XML 名必须一一对应。VOC 数据集的命名规则是严格同名的但手动整理数据时经常出现图片是frame_001.jpg、XML 却是frame_1.xml的情况。我会在转换前先跑一遍交叉比对找出有图无标注、有标注无图的两类文件宁可删掉也不要让脚本在中间突然中断。第二个检查点是类别名统一。VOC 官方数据集里是person、car这种小写格式但自己标注时很容易混入Person、Car这样的写法。转换脚本遇到这类标注会直接跳过训练时 mAP 曲线可能一直在零附近。解决办法是在parse_xml里统一转小写或者转换前做一个类别统计把出现次数最少的类别名打印出来人工确认。第三个检查点是边界框坐标是否越界。标注软件偶尔会把框拉到图片外面出现xmax大于图片宽度的情况。COCO 格式允许 bbox 超出边界但 YOLOX 的数据增强会因此产生奇奇怪怪的裁剪训练损失容易波动。我一般会在转换脚本里加一个裁剪逻辑把 bbox 的右下角限制在图片宽高范围内再做下一步。4. 训练自己的数据集配置参数怎么改命令怎么跑4.1 底检测器选 YOLOX 的原因和 ByteTrack 配套的适配成本最低ByteTrack 的跟踪模块是检测器无关的理论上接 YOLOv5、YOLOv8 或者 Faster R-CNN 都能跑。但官方仓库的 demo 脚本、配置文件和权重转换工具都是按 YOLOX 写的第一次复现时选 YOLOX 能少踩很多适配的坑。YOLOX 本身是个无锚框检测器不需要像 YOLOv5 那样聚类算 anchor训练流程简洁部署时用 TensorRT 加速也有现成方案。如果你之前用过 YOLOv5并且已经标注好了自己的数据集那只要把标签从 YOLO 的 txt 格式再转回 COCO JSON 即可。但第一次跑通 ByteTrack我不建议折腾其他检测器直接用仓库里自带的yolox_s或者yolox_m把类别数和数据路径改掉就行。检测器的精度直接决定跟踪上限检测框漏了跟踪器再聪明也补不回来。4.2 改配置classes、数据路径、学习率和 batch sizeByteTrack 仓库里的 YOLOX 实验配置长这样我按自己的数据集改过一份# exp.py 基于 exps/example/yolox_s/yolox_s.py 修改 from yolox.exp import Exp as MyExp class Exp(MyExp): def __init__(self): super().__init__() self.num_classes 2 self.data_dir /data/datasets/VOC2COCO self.train_ann train.json self.val_ann val.json self.max_epoch 100 self.data_num_workers 4 self.input_size (640, 640) self.test_size (640, 640) self.random_size (14, 30) self.base_lr 0.01 self.warmup_epochs 5 self.eval_interval 10num_classes要和你转换 JSON 时的类别数一致类别名列表里的顺序也要匹配。比如你只检测 person 和 car这里就是 2COCO JSON 里的 category_id 从 1 开始脚本已经处理好了。data_dir指向存放train.json和val.json的目录train_ann和val_ann只写文件名。input_size和test_size是训练和测试时的图片尺寸。显存紧张时可以把 input_size 改成 416但小目标召回率会下降显存足够我一般保持 640。random_size是 YOLOX 的多尺度训练参数表示每次迭代在 14 到 30 倍之间随机取一个尺度范围越大增强越强但也更吃显存。base_lr是初始学习率单卡 batch size 为 16 时 0.01 是默认值。如果你的 batch size 只有 4 或 8我建议把学习率降到 0.001 到 0.005否则前几个 epoch 特别容易出现 loss 直接 NaN 的情况。4.3 启动训练和观察日志看 loss 而不是只看 mAP配置改完后单卡训练命令如下python -m yolox.tools.train -f exp.py -b 8 --fp16 -o -c pretrained/yolox_s.pth命令里的-b 8是 batch size--fp16开启混合精度训练显存不够时很有用。-o表示占用显存自动选择 batch size-c加载预训练权重建议一定要加从零训练收敛速度会慢很多。多卡训练时把-b改成总 batch size再额外加一个-d参数指定卡数python -m yolox.tools.train -f exp.py -d 4 -b 32 --fp16 -o -c pretrained/yolox_s.pth训练启动后我一般主要看两个地方一个是 loss 曲线是否稳定下降另一个是验证集 mAP。但 mAP 只反映检测质量跟踪效果还要另外跑 MOT 评估。YOLOX 的日志会输出每个 epoch 的 loss 和 mAP如果 loss 下降但 mAP 长期不动优先回去查数据转换脚本大概率是训练集和验证集有重叠或者类别名映射出了问题。训练完成后权重文件会保存在YOLOX_outputs/exp_name/best_ckpt.pth.tar后面摄像头实时检测用的就是这个文件。5. 避坑从训练到跟踪的 5 个常见翻车现场5.1 验证 mAP 为 0类别名大小写不一致现象训练 loss 正常下降但验证集 mAP 始终在 0 附近偶尔跳一下又掉回零。原因XML 里写的是Person转换脚本的类别列表里写的是person导致所有目标都被跳过。训练时 loss 看起来在降其实是在学“空图”。这个问题在没有认真统计标注类别的项目里非常常见。解决转换脚本里把所有类别名统一转小写并在脚本main里增加一段统计代码打印每个类别的目标数量。看到数量明显不正常的类别直接回标注软件里查。5.2 loss 前几个 epoch 就 NaN学习率过大或标注越界现象训练到第 3 到第 5 个 epochloss 直接变成 NaNtensorboard 曲线断掉。原因两个因素叠加一是 base_lr 太高二是标注框里存在xmin xmax的情况计算 IoU 时出现除零或负数梯度。我自己遇到过一次一个目标的 bbox 四个坐标全是同一个点训练直接崩。解决先跑一遍标注清洗脚本过滤掉所有宽或高小于等于 0 的框然后把base_lr降到 0.001。开--fp16时如果还出现 NaN可以换用更大的批大小或关闭 AMP。5.3 跟踪时 ID 疯狂切换track_thresh 设太低现象同一个测试视频里其他参数没动把track_thresh从 0.5 降到 0.1 后跟踪框数量暴增ID Switch 比论文结果高好几倍。原因低置信度检测框里混入大量误检第二次关联时轨迹被反复打断或重连状态机不停做销毁和重建。ByteTrack 的低分框补救机制依赖“低分框位置准确”这个前提前提不成立时阈值越低效果越差。解决track_thresh保持默认的 0.5 左右第一次跑通后再根据检测框置信度分布微调不要一步到位调太低。match_thresh也不要盲目往高调IoU 匹配太严格目标稍微转个身就丢轨迹。5.4 摄像头画面延迟越来越大OpenCV 缓冲区堆积现象本地 USB 摄像头或 RTSP 流刚启动时实时性还行运行十几分钟后画面越来越卡延迟肉眼可见。原因OpenCV 默认会缓冲多帧图像处理线程速度跟不上时读出来的全是旧帧。跟踪器一直在追早该显示的画面延迟只会越来越大。RTSP 流更容易出现这个问题网络抖动时缓冲区被塞满。解决用 OpenCV 打开视频流后把缓冲区强制设成 1import cv2 cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)RTSP 场景下这个参数有些摄像头驱动不支持但设置后通常能明显降低延迟。如果还不行就换一个专为 IO 优化的读取线程用队列只保留最新帧。5.5 评估指标和论文对不上验证据集混入训练集现象自己在 VOC 上训练的模型检测 mAP 比官方模型低一大截跟踪 MOTA 也上不去。原因很多人习惯把整个数据集随机分成训练和验证但 VOC 官方划分是固定的图片可能来自同一段连续视频随机划分会导致训练集和验证集高度相似验证指标虚高或虚低没有参考价值。解决严格使用ImageSets/Main里自带的train.txt和val.txt划分不要自己随机分。验证时用test_size而不是input_size多尺度训练后直接用训练尺寸做验证结果会偏低。6. 摄像头实时检测跟踪从本地摄像头到 RTSP 的一条命令模型训练完成后接摄像头实时检测跟踪只需要一条命令。ByteTrack 仓库里的 demo 脚本支持 USB 摄像头、RTSP 流和本地视频文件三种输入python tools/demo_track.py --demo webcam --camid 0 --path 0 \ -f exp.py \ -c YOLOX_outputs/exp_name/best_ckpt.pth.tar --fp16 --fps 30如果你用的是海康威视或大华的网络摄像头--path直接填 RTSP 地址就行例如python tools/demo_track.py --demo webcam --camid 0 \ --path rtsp://192.168.1.64:554/Streaming/Channels/101 \ -f exp.py -c YOLOX_outputs/exp_name/best_ckpt.pth.tar --fp16RTSP 地址可以从摄像头的配置页面里复制不同品牌路径格式略有差异但rtsp://开头的基本结构都差不多。跟踪器参数有三个值得单独调track_thresh控制哪些检测框进入第一次关联match_thresh控制 IoU 匹配的松紧track_buffer控制轨迹丢失后保留多久。第一次跑通时保持默认值不要急着改等检测框稳定了再微调。如果 FPS 不达标先确认开了--fp16然后换小模型或者把input_size降到 416。再不行就用 TensorRT 加速ByteTrack 官方仓库里有现成脚本。从那以后我每次做摄像头项目都强制走一遍固定流程先用静态图片验证检测器再跑一段录制视频看跟踪稳定性最后才接摄像头实测避免在调试现场改参数改到崩溃。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

从零构建一个 Harness-on-the-Loop 系统:用 TaoToken 统一 Key 打通多模型调用链路 2026/10/1 19:51:46

从零构建一个 Harness-on-the-Loop 系统:用 TaoToken 统一 Key 打通多模型调用链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
SuperDriver 与 WFP:Windows 内核驱动防火墙过滤实战 2026/10/1 19:51:46

SuperDriver 与 WFP:Windows 内核驱动防火墙过滤实战

简介:这份资源是面向Windows内核开发与网络安全方向学习者的WFP网络驱动防火墙源码,适合具备一定驱动开发基础、希望深入理解Windows过滤平台(WFP)架构的开发者参考。它可用于研究网络数据包拦截、过滤规则下发与驱动层通信等典型…

阅读更多 →
OpenClaw 产品分析报告:本地优先 AI Agent 的架构拆解与 TaoToken 接入实践 2026/10/1 19:51:46

OpenClaw 产品分析报告:本地优先 AI Agent 的架构拆解与 TaoToken 接入实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
社区闲置物品交易系统实战:微信小程序+Node.js全栈开发 2026/10/1 19:51:46

社区闲置物品交易系统实战:微信小程序+Node.js全栈开发

小区里的二手钢琴闲置了两年,隔壁邻居想给小孩买辆平衡车却嫌全新太贵,楼上的阿姨攒了一堆育儿书不知道往哪送。我在社区群里观察这些需求很久了,类似的消息每天都有,但没有一个地方能把它们系统化地承接起来。所以我自己做了一个…

阅读更多 →
清华开源AI课堂OpenMAIC:基于LangGraph多智能体协作实现互动视频生成 2026/10/1 19:51:45

清华开源AI课堂OpenMAIC:基于LangGraph多智能体协作实现互动视频生成

1. 从“AI课堂”到“互动视频生成器”:这个项目到底在解决什么问题第一次看到“清华开源AI课堂”这个说法,我下意识以为又是一个把PPT套上大模型外壳的演示项目。直到我把 OpenMAIC 的代码拉下来跑通,才意识到它想做的事情要激进得多&#xf…

阅读更多 →
【Bug已解决】openclaw memory allocation failed / Cannot allocate memory — OpenClaw 内存分配失败解决方案:用 TaoToken 2026/10/1 19:51:38

【Bug已解决】openclaw memory allocation failed / Cannot allocate memory — OpenClaw 内存分配失败解决方案:用 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉