搞目标跟踪的人,对PyTracking这个名字应该都不陌生。它不是一个单独的算法,而是一整套训练和评测跟踪器的代码框架,常年被用来复现ATOM、DiMP、PrDiMP、Super_DiMP、KYS这些经典工作。我见过不少朋友把仓库拉下来之后,先是被乱七八糟的配置文件劝退,再是卡在数据集下载和目录对齐这步,最后好不容易跑起来,又发现训练日志里的loss曲线跟论文完全对不上。这篇文章就围绕PyTracking这套代码,把我自己跑ATOM到KeepTrack这一路踩过的坑、捋清楚的逻辑、改过的配置,一次性写清楚。
文章适合谁看?两类人:第一类是刚入门目标跟踪、想用现成框架复现经典模型找手感的研究生;第二类是已经跑通过一两个模型,但对内部训练流程、六个模型之间的差异还比较模糊的开发者。读完之后,你应该能自己搭好环境、配好数据集、把训练跑起来,并且知道每个模型的训练入口和注意事项。
1. 认知先行:PyTracking和六个跟踪器是什么关系
1.1 为什么说PyTracking是“跟踪训练全家桶”
PyTracking本质上是一套以深度学习目标跟踪为核心的训练框架,它把数据加载、样本采样、模型定义、训练循环、评测脚本全部封装好了。你不需要像早年做跟踪那样,自己手写一堆dataloader和优化器调度逻辑,只需要在配置层面指定用哪个模型、哪份数据集、多大batch size,就能把一次完整的训练跑起来。
整套框架的关键结构可以拆成三层:
- 训练层:负责读取视频序列、裁剪模板帧和搜索帧、数据增强、计算损失、反向传播。
- 模型层:包含各个跟踪器专用的网络结构,比如DiMP的判别模型预测模块、PrDiMP的概率回归头。
- 评估层:提供在VOT、LaSOT、TrackingNet、GOT-10k等平台上的离线测试接口。
我个人的理解是,PyTracking把“跟踪器的训练流程”做成了标准化流水线,真正让你花时间的反而是怎么适配自己的数据和改损失函数。理解了这一点,再去看六个模型,它们就不是六个毫无关联的算法,而是在同一套流水线上迭代出来的家族。
1.2 六个模型各自的定位和继承关系
先列出我对这几个模型的理解,后面训练部分会逐个展开:
| 模型 | 核心思路 | 与前一模型的关系 | 训练侧重点 |
|---|---|---|---|
| ATOM | 用IoU预测来代替传统分类得分,通过最大化重叠来精确定位 | 早期代表,Proposal-based跟踪思路 | 回归训练,依赖高质量的proposal |
| DiMP | 把判别模型的更新过程建模成网络预测,在线学习目标模型 | 继承ATOM的IoU预测,加入判别模型 | 需要同时训练特征提取器和判别模型预测器 |
| Super_DiMP | 通过更强的监督信号和训练策略提升DiMP | DiMP的增强版 | 数据增广、更难样本挖掘 |
| PrDiMP | 用概率化回归(KL散度)替代普通L2损失,让预测分布更可靠 | DiMP家族的贝叶斯化变体 | 概率头训练,损失函数改动明显 |
| KYS | 不只盯目标本身,还联合周围上下文目标的运动状态来辅助定位 | 独立方向,强调“知道周围发生了什么” | 需要多目标上下文标注,训练数据组装更复杂 |
| KeepTrack | 长期跟踪稳定性,侧重目标消失重现时的记忆处理 | 跟随该框架的新近实现,结构上和DiMP家族接近 | 需要长序列数据,训练策略偏向持久化 |
这个顺序其实也基本对应了目标跟踪这个方向近几年的演化思路。最早大家死磕“怎么判得更准”,后来发现“怎么更新模型”更关键,再后来开始考虑概率化表达、周围上下文、长期记忆。PyTracking把这一连串进展都落成了可跑的代码,所以你在训练时深刻理解数据是怎么送的,就相当于看懂了一半。
2. 环境配置:先把坑填完再谈训练
2.1 依赖版本怎么选
学习这些老模型,最容易栽的跟头就是环境版本问题。PyTracking最早的设计基于PyTorch 1.1到1.4这个区间,很多内部实现用到了当时比较新的API,如果你拿PyTorch 2.x直接跑,大概率会碰到算子改名甚至接口行为不一致的问题。
我自己的建议是:创建一个独立的conda环境,使用Python 3.7,安装PyTorch 1.4.0 + torchvision 0.5.0。这套组合在旧代码里匹配度最高,不怎么需要改源码。
conda create -n pytracking python=3.7 conda activate pytracking pip install torch==1.4.0 torchvision==0.5.0 pip install matplotlib pandas tqdm tb-nightly pyyaml opencv-python装完后,最好先写个两行脚本确认torch.cuda.is_available()是True,同时看一眼GPU算力。如果是近两年的新卡,比如Ampere架构或者更新的架构,PyTorch 1.4的CUDA版本可能认不出显卡算力,这种时候不要死磕老版本,换到PyTorch 1.7、1.8甚至1.10都行,代价是可能需要修复小部分代码兼容问题。
注意:训练环境和测试环境尽量保持一致。我遇到过训练用1.4、测试用1.8的情况,虽然模型能加载,但输出结果跟训练时不一致,排查了半天发现是插值算子的对齐方式变了。
2.2 数据集准备与目录约定
PyTracking的训练数据主要依赖几大公开跟踪数据集:LaSOT、TrackingNet、GOT-10k、VOT2018/2019。每个数据集的标注格式都不一样,LaSOT和TrackingNet以图片序列加边界框为主,GOT-10k有自己的标注文件结构。第一次跑的时候,并不是下载完就能直接用,你需要改成代码里约定的目录结构。
框架里通常在配置文件中维护一个data_path字段,然后代码会按照固定子目录去寻找视频帧和标注文件。大致结构如下:
$YOUR_DATASET_ROOT/ ├── lasot/ │ ├── airplane-1/ │ │ ├── img/ │ │ │ ├── 00000001.jpg │ │ │ ├── 00000002.jpg │ │ └── groundtruth.txt ├── got10k/ │ ├── train/ │ │ ├── GOT-10k_Train_000001/ │ └── test/ └── trackingnet/ └── frames/用自己的数据集路径时,不要直接改代码里的硬编码,优先改配置文件。如果硬盘空间紧张,Linux下建议用软链接指向真实数据目录,能省不少事:
ln -s /data/sda/lasot $HOME/datasets/lasot ln -s /data/sda/got10k $HOME/datasets/got10k2.3 预训练模型和可能需要的预处理
PyTracking训练时通常需要一个在ImageNet上预训练过的backbone,一般用ResNet系列。代码里会通过配置文件指定预训练权重的路径。少这一步,loss虽然也能跑,但前期收敛极慢,而且训练结果很可能跟论文差一大截。
如果你打算从零开始训练整个网络,还需要注意数据预处理的一致性。比如LaSOT里图像尺寸各不相同,代码会先做resize和归一化,然后按照模板帧大小、搜索帧大小裁剪出对应的patch。这些预处理参数很多都写在配置里,不要随手修改,改一处可能就影响后面的数据增强和正样本定义。
我自己在准备数据时走过一次弯路:下载了完整的LaSOT测试集但忘记下载训练子集,训练时dataloader一直读到空数据,看起来像是卡死。后来才反应过来是路径下根本没有相应的帧文件夹。所以下载完成后,最好先写个脚本统计一下每个子集的视频数量,跟官方说明对一下。
3. 训练入口:配置、命令、日志三板斧
3.1 配置文件应该怎么读
PyTracking里每一种模型都有一套配置文件,通常包含模型名、使用哪块训练数据、batch size、学习率、训练轮数、损失权重等。以常见的DiMP配置为例,里面会有类似下面的内容:
{ "model": "dimp", "backbone": "resnet50", "output_dir": "checkpoints/dimp", "dataset": ["lasot", "trackingnet", "got10k"], "batch_size": 16, "num_epochs": 50, "num_workers": 8, "learning_rate": 0.001, "lr_drop": 40, "train_backbone": False, "train_iou_head": True, "loss_weights": { "cls": 1.0, "iou": 1.0 } }训练之前,打开配置文件逐项确认:
- train_backbone一般设为False,真要从头微调backbone,显存和时间开销会成倍增长。
- num_epochs不是越大越好,很多模型在后半段会出现过拟合,验证指标反而下降。
- loss_weights的比例直接影响最终性能,尤其是ATOM这类以IoU为主的模型,iou loss权重要足够大。
3.2 启动训练和监控
框架一般会提供一个统一的训练入口脚本,运行方式大致是:
python run_training.py --train_module atom --train_name atom_res50这里要在项目根目录下运行,train_module指定模型模块,train_name指定具体的配置文件别名。启动之后,日志会输出到output_dir,TensorBoard的信息也会同步记录。建议训练时随时盯着两类曲线:
- 总loss曲线:应该在几十个iter后开始稳定下降。
- 各分项loss曲线:比如DiMP的判别损失和IoU损失,二者下降速度不一致是正常的,但如果某一项长期不动,就需要检查数据正负样本比例。
这个框架的日志打印频率不算高,前期建议每50个iter手动看一眼loss数值,判断是否有NaN。
3.3 保存的checkpoint与推理测试脚本
训练结束后,每个epoch会保存模型权重,PyTracking也提供了对应的测试脚本,用来跑官方评测集。测试时指定权重路径,脚本会在给定数据集上逐序列初始化第一帧目标框,然后持续输出预测框,最后用工具包统计成功率AUC和准确率之类的指标。
我在实际测试中发现,同一个模型在不同数据集上的表现差异很大。比如在LaSOT上表现不错的权重,放到TrackingNet上不一定好,因为两者的视频长度、目标外观变化幅度都不同。所以训练和测试必须对齐论文里使用的数据集组合,才谈得上复现。
3.4 评估指标到底看什么
跟踪领域常用的评估指标包括:
- 成功率图(Success Plot)和其AUC值:反映在不同重叠阈值下的成功比例。
- 精确率图(Precision Plot):中心位置误差的累计曲线,一般报告20像素或论文指定阈值。
- GOT-10k的AO和SR:GOT-10k特殊协议下的平均重叠率与成功率。
新手容易犯的错误是只盯着终端里打印的最后一行总指标,却忽略不同测试序列上的分布。很多跟踪器是在容易序列上强,在长时遮挡序列上崩掉。建议评测时把指标按序列属性拆开看,后面调训练策略会更有方向。
4. 六个模型的训练差异逐个说
4.1 ATOM:打地基的IoU回归训练
ATOM的核心是用IoU预测代替传统的分类得分,它把目标跟踪建模成“从一堆候选框中选出和真实目标重叠最大的那个”。训练时,网络接收模板帧和搜索帧两个分支,然后通过IoU预测头输出每个候选框的重合度。
训练ATOM时要重点注意候选proposal的生成方式。代码里采样的proposal如果偏移量太小,IoU预测头很快就能学会,但实际跟踪时搜索范围一大就抓瞎;偏移量太大,正样本太少,损失波动很明显。我自己用过的一个trick是适当增加中等偏移范围的proposal占比,让模型见过更多“难分好坏”的样本,跟踪时能更稳一点。
ATOM的另一个特点是它不强调在线模型更新,所以在长时视频里容易出现漂移。如果你用ATOM做基线,别指望它像DiMP那样遇到干扰后能自我纠正。
4.2 DiMP和Super_DiMP:把“判别力”训练出来
DiMP相比ATOM最大的变化,是把传统相关滤波里的判别模型更新过程,硬生生地用神经网络预测出来了。它的训练不再只是“识别目标长什么样”,而是“针对当前帧构造一个判别模型来区分目标和背景”。训练DiMP的时候,你要关注两个阶段性的loss曲线回落:
- 第一阶段是初始分类损失快速下降,网络先学会基本的目标/背景分类。
- 第二阶段是模型预测器在难负样本上的表现,这部分会决定最终判别力上限。
Super_DiMP不只是加大训练数据那么简单。它更强调在训练时使用更强数据增广、更合理的负样本采样策略,顺便优化了IoU头和判别头的协作方式。训练Super_DiMP时,除了看loss,更要关注训练集和验证集之间的gap。我在跑Super_DiMP时,发现它在验证集上的AUC增长会在某个epoch后明显变缓,但训练loss还在降,这时候继续硬train反而不利于泛化。
4.3 PrDiMP:概率回归的KL散度怎么做训练
PrDiMP在DiMP的基础上把定位问题概率化,它不再让网络强行回归一个唯一的框坐标,而是输出一个概率分布,然后用KL散度来度量预测分布和真实分布的差异。这种改动带来的训练影响是,loss曲线没有之前那么“直观”,你看到的数值可能更大,但并不意味着训练变差。
训练PrDiMP时,最重要的配置是把KL散度损失的缩放权重调好。如果权重偏小,概率头会很快坍缩成一个尖峰,但位置并不准;如果权重偏大,模型变成了“不求最好,只求别错”,边界框会偏保守。我在实验里通常会先保持默认权重,观察定位精度指标变化后再微调。
还有一个训练技巧是降低batch size、适当增加训练轮数。PrDiMP对单个样本的拟合要求更高,batch太大反而容易出现平均化效应,导致预测分布过于平滑。
4.4 KYS:训练时还要引入周围目标
KYS的思路比较特殊:它不只是看被跟踪目标,还要“知道周围发生了什么”。比如,当目标旁边出现一个相似外观的物体时,KYS会利用周围目标的运动信息来调整对当前目标的置信度。这就让训练数据的组织比前几个模型复杂得多。
训练KYS前,请先确认你的数据集是否带有多目标的上下文标注。某些数据集只有单目标标注,直接拿来训练KYS会缺失上下文分支的监督信号。我当时的做法是选用标注相对丰富的子集,单独写一个数据筛选脚本,把同一序列里共现目标的帧都挑出来,然后配置里把这个子集路径指向KYS专用的数据入口。
KYS训练时的计算开销也更高,因为它除了主线特征,还要额外提取周围目标的状态特征。如果你的显卡显存只有11G级别,batch size往往需要降到个位数,此时配合梯度累积可以稳住训练稳定性。
4.5 KeepTrack:不太一样的训练配置
KeepTrack在框架里更像是把长期记忆机制引入跟踪的一次尝试。它训练时比较吃长序列数据,因为只有足够长的视频才能让“目标消失再重现”这类情况被模型充分学习。如果你手中的数据集大多是短序列,训练KeepTrack时可以考虑把多个短序列拼接成伪长序列,前提是拼接处的边界要处理好,别让模型学到“跳变即消失”的错误规律。
训练KeepTrack最需要注意的是checkpoint的选择,它的效果对预训练权重非常敏感。如果是从DiMP全套权重起步,迁移会顺很多;如果是随机初始化,训练周期会被显著拉长,而且最终效果很难达到预期。我个人在实验时是先用DiMP的流程把backbone和其他共享部分训到一定水平,再切到KeepTrack的配置文件做继续训练。
5. 训练中的常见问题与排查实录
5.1 显存不足:batch size砍半还不够
很多人在8G或11G显存的卡上训练,一上来就按默认batch size跑,结果OOM。最直接的办法是减小batch size,但太小会影响BN统计量。我的推荐顺序是:
- 把batch size降到4或8,同时适当增大梯度累积步数,模拟大batch效果。
- 降低搜索帧的裁剪分辨率,这个对显存影响非常显著。
- 如果还有余量,使用混合精度训练,但要注意老代码里的某些算子可能不支持fp16,需要先在小规模数据上验证loss能正常下降。
有个容易被忽略的点是num_workers开太大也会占显存,尤其数据增强如果涉及大量裁剪操作,子进程的内存复制会显著提升整体显存开销。我一般会把num_workers控制在4到6。
5.2 loss不收敛或崩掉
训练最常见的问题就是loss在某个iteration突然变成NaN,或者始终在一个高水位震荡。遇到这类情况,按照下面的顺序排查:
- 检查数据标签是否有空框、负坐标、越界框,数据清洗是第一步。
- 检查学习率是不是太大,尤其是多卡训练时学习率需要按卡数线性缩放。
- 检查预训练权重加载是否正确,随机初始化的backbone容易让loss前期跳变严重。
- 检查损失函数里的归一化项,比如KL散度或者IoU Loss在极端重叠情况下,数值可能溢出。
我踩过最深的一个坑是数据集中存在重复帧,某些序列在拼接时帧顺序错乱,导致前后帧目标位置完全无关。模型训练时loss看起来能降,但评测时几乎跟丢所有目标。后来我写了一个脚本检测相邻帧目标框的IoU,把异常序列全筛出来才发现问题。
5.3 测试结果与论文差距很大
训练loss不错但测试效果差,通常不是模型没学好,而是评测协议或者初始化偏差。常见原因包括:
- 第一帧目标框的读取方式跟论文不一致,比如是否做了边界裁剪。
- 测试时搜索区域的大小设置和训练时不一致,导致模型没见过这种尺度。
- 后处理阈值不同,尤其是DiMP家族中的更新阈值,它对结果影响极大。
建议先拿到官方提供的预训练权重,在你本地跑一遍测试,确认你的评测环境和官方结果一致后,再替换上自己训练的权重。这样能把“环境问题”和“训练问题”在逻辑上切开。
5.4 问题速查表
| 现象 | 可能原因 | 处理方案 |
|---|---|---|
| 启动训练直接OOM | batch size过大、搜索帧分辨率高 | 降batch、降分辨率、加梯度累积 |
| loss是NaN | 学习率过大、数据含异常标注、归一化溢出 | 清洗数据、降学习率、检查损失项 |
| 训练loss降但评测差 | 评测协议不一致、后处理阈值不当 | 先用官方权重对齐评测环境 |
| 不同数据集指标差异大 | 训练数据组合与目标场景不匹配 | 按论文组合数据或增加对应域数据 |
| 模型前期稳后期崩 | 跟踪模型未及时更新或更新过度 | 调整在线更新阈值,观察模型预测器 |
| KYS训练时报上下文数据错 | 数据集缺少多目标标注 | 改用含丰富上下文标注的子集 |
6. 一些个人实战体会
整套PyTracking框架跑下来,我最大的感触是:训练代码本身没什么神秘可言,真正的门槛全在数据和配置细节上。比如同一个DiMP模型,用不同的数据组合训练,结果能差出好几个点;同一个PrDiMP配置,在Windows和Linux上跑出来的数据加载顺序都可能不一样。所以如果你打算拿这套框架做实验,强烈建议一开始就建立一个固定的“环境快照”,包括Python版本、PyTorch版本、数据集目录、配置文件全部锁死,这样后续对比实验才有意义。
另外,如果只是刚接触目标跟踪,不建议一上来就啃KYS或者KeepTrack,先把ATOM和DiMP跑通,理解它的训练循环、评测流程,再看后面那些复杂模型,你会轻松很多。跑通确实不难,难的是过程中的每一个细节你都弄明白。希望这篇文章能让你少走一些我走过的弯路。