☰
FairMOT核心解读:无锚点检测与Re-ID公平共享特征的多目标跟踪基线
2026/10/14 13:43:24 网站建设 项目流程

聊到多目标跟踪,绕不开一个现象:检测框很准,但同一个人的 ID 老变。明明人还在画面里,ID 却从 3 跳到 17,再跳回 3,视频看着就好像人物在“闪烁”。FairMOT 这篇论文最打动我的地方,就是它把这个问题从“调参”上升到了“结构设计”:检测和重识别(Re-ID)两个任务在同一个网络里共享特征,天然会打架,而它用无锚点(anchor-free)方式把两者之间的偏见尽量抹平,让跟踪结果在拥挤、遮挡和小目标场景下稳定了不少。

如果你想搞懂 MOT 的联合检测与跟踪范式,或者正在复现一个能跑的跟踪基线,这篇论文值得细读。它不追求花哨的模块,而是把“公平性”这个设计目标讲得很清楚:检测任务和 Re-ID 任务到底是怎么共享特征的、为什么基于锚框的方法会偏袒检测、中心点采样为什么更适合取外观特征。下面我会按设计动机、网络结构、训练损失、推理关联、实验对比和复现避坑这个顺序来拆,尽量把论文里的关键细节和我自己踩过的坑都讲透。

1. FairMOT 到底在解决什么问题?

多目标跟踪的核心需求很简单:每一帧里既要找到目标的位置,又要保持目标身份的一致性。传统做法是“先检测后跟踪”,也就是 Tracking-by-Detection,先用一个检测器给出所有目标的边界框,再用卡尔曼滤波、匈牙利匹配这些东西把框串成轨迹。这套流程特别成熟,但有个固有缺点:检测和跟踪是两套模型,检测出的框稍微抖一下,跟踪结果就要跟着一起抖,而且检测器本身不关心身份信息,遇到遮挡和重叠时很容易串 ID。

后来学术界开始做联合检测与跟踪,也就是 Joint Detection and Tracking,把检测和嵌入特征提取放在同一个网络里。FairMOT 就属于这一类。它的全称对应的论文标题是 A Simple Baseline for Multi-Object Tracking with Anchor-free Detectors,核心思路是用一个无锚点检测器同时输出目标边界框和 Re-ID 特征,再通过外观距离做数据关联。

1.1 多目标跟踪的主流范式与关键指标

要读懂 FairMOT,得先搞清楚 MOT 的评价体系。最常看到的三个指标是 MOTA、IDF1 和 ID Switch。

MOTA 看起来像“准确率”,其实是一个综合了漏检、误检和 ID 切换的分数,更偏向检测质量。IDF1 则关注身份匹配的 F1 值,它衡量的是“每个轨迹中被正确保留身份的比例”,更偏向跟踪质量。ID Switch 就是前面说的那种 ID 跳变次数,一个视频里 ID 反复横跳,哪怕检测框都很准,IDF1 也会很难看。

这也是为什么只看 MOTA 会误判一个跟踪器的好坏。有些方法检测很强,但每帧都重新给目标分配身份,MOTA 看着不低,实际视频效果却非常糟糕。FairMOT 最聪明的地方,就是它把 IDF1 和 ID Switch 当成核心优化目标来设计网络,而不是只把检测精度堆上去。

1.2 “不公平”这个切入点到底在说什么

FairMOT 这个名字来自 fairness,准确说是检测任务和 Re-ID 任务在共享网络中的“公平性”。论文作者发现,当时很多联合检测与跟踪方法,本质上都是把检测器里加一个 Re-ID 分支,比如在基于锚框的检测器上做 ROI 特征提取,再接一个身份分类头。这种做法有个隐蔽问题:anchor 天生是为目标检测服务的,用它来框选 Re-ID 特征提取区域,其实对身份特征非常不友好。

举个例子,一个行人在被遮挡时,检测框往往把旁边另一个行人的胳膊、路牌、背景墙都包进来。如果 Re-ID 特征是从整个边界框区域提取的,那网络的注意力就被分散了,学到的嵌入自然不稳定。FairMOT 认为,这种“锚框采样 + 区域特征”的做法让两个任务在梯度上互相踩踏:检测分支想让特征把前景和背景分得更开,Re-ID 分支想让特征把所有目标 ID 分得更细,两个目标在同一个特征图上拉扯,最后检测赢了,Re-ID 输了,结果就是跟踪时 ID 频繁切换。

所以 FairMOT 要做的不是简单调大 Re-ID 损失权重,而是从结构上消除这种偏见:用无锚点检测器,从目标中心点提取外观特征,把特征分辨率也提高到原来的 4 倍。中心点天然是目标最具代表性的位置,相比锚框和整框 ROI,它的语义更纯粹,也不容易把周围干扰包进来。

2. FairMOT 的整体设计拆解

FairMOT 的结构并不复杂,但每个设计点都有明确动机。它的骨干网络采用了一个改进版的 DLA-34,在高层特征和低层特征之间做多层聚合,然后分出两个分支:一个分支负责预测中心点热图、目标宽高和中心偏移,另一个分支负责生成逐像素的 Re-ID 嵌入图。两者共享骨干特征,但在分支上层各干各的活。

这个设计和当时的 JDE 类方法有个本质区别:不是“在检测头旁边加一个 Re-ID 头”,而是“把 Re-ID 需要的位置采样方式从锚框区域换成目标中心点”。而“无锚点”不只是一种目标检测的流派选择,它直接改变了 Re-ID 特征的获取方式。

2.1 为什么选无锚点检测器,而不是基于锚框的方案

基于锚框的检测器,比如经典的 Faster R-CNN 或 YOLO 系列,会预设一堆固定大小、长宽比的锚框,然后判断这些锚框里有不有目标。问题在于,Re-ID 需要一个“属于该目标”的特征向量,而从锚框区域里抠特征,本质上是让网络在预设的框里做池化,特征质量取决于这个框和真实目标的贴合程度。

无锚点检测器的思路不一样。它直接在特征图上预测目标中心点落在哪个位置,然后在中心点处取 Re-ID 嵌入。大家可以理解成:检测负责找到“这个人的中心点在哪”,Re-ID 负责回答“这个人是谁”。中心点对尺度不敏感,也不包含边界框里的大量背景像素,所以“把检测和 Re-ID 放在同一个特征图上”这件事变得顺理成章。

这里有个很重要的细节:无锚点检测器通常不需要 NMS。传统检测器要靠 NMS 把重复框去掉,但 NMS 的 IoU 阈值调不好会误删同一目标,或者把两个很近的目标合并成一个。FairMOT 通过中心点热图的局部极大值来定位目标,每个目标只保留一个中心候选,少了这条容易产生连锁错误的路径,跟踪阶段也更干净。

2.2 网络结构细节:改进的 DLA-34

FairMOT 的骨干网络选了一个看起来“不够新”的 DLA-34,但论文在它身上做了两件对 MOT 至关重要的事:多层特征聚合和输出分辨率提升。

DLA-34 本身是一种带层级聚合的骨干网络,它不像 FPN 那样只做简单的自顶向下融合,而是把不同层级的特征多次交叉融合,深浅层之间信息流非常密集。这样得到的特征图,既有高层的语义信息,又有低层的细节纹理,对小目标和遮挡目标的表示能力比直接用 ResNet 这类普通骨干更好。

更关键的是,FairMOT 把输出 stride 从常见的 8 或 16 降到了 4。你可以算一下这个差距:假设输入是 1088×608,输出 stride 如果是 8,特征图就是 136×76,一个 32×32 像素的小目标在这张特征图上只占 4×4 个像素;如果 stride 是 4,特征图变成 272×152,同一个目标能占 8×8 个像素。对目标检测来说 4×4 勉强够用,但对 Re-ID 来说,4×4 的嵌入区域根本学不出稳定的身份特征,稍微遮挡一下就完全废了。所以 4 倍下采样不是工程上的小改动,而是让 Re-ID 分支在小目标上“活过来”的必要条件。

2.3 检测分支与 Re-ID 分支并行输出

在 DLA-34 的末端,FairMOT 并行接出两个分支。检测分支产生三个输出:中心点热图(H/4 × W/4 × 类别数)、目标宽高(H/4 × W/4 × 2)以及中心偏移(H/4 × W/4 × 2)。Re-ID 分支产生一个嵌入图(H/4 × W/4 × 128),也就是说特征图上每一个位置都对应一个 128 维向量。

这个“逐像素输出嵌入”的设计,可能刚开始会让人疑惑:为什么不在目标中心附近直接接一个全连接层?答案是,模板多变、分辨率要求高。如果只在固定位置提取嵌入,网络没法适应目标出现在任意位置的情况,而逐像素生成嵌入图,相当于让每个空间位置都能独立回答“我是谁”。推理时,我们只需要用检测到的中心点坐标,去嵌入图的对应位置取一个向量,过程非常直接。

两个分支共享底层特征,但到了高层各算各的损失,梯度回传时会互相影响。FairMOT 的做法不是为了完全隔离两个任务,而是让它们在足够好的共享特征之上各取所需:检测需要知道“哪里是前景、边界在哪”,Re-ID 需要知道“这个位置的视觉特征可以用来区分不同身份”。这种结构上的并行,比在同一个特征图上硬接多个头的做法要清晰得多。

3. 训练细节与损失函数:多任务学习怎么不“失衡”

FairMOT 的训练目标可以拆成三部分:中心点热图的分类损失、边界框尺寸的回归损失,以及 Re-ID 嵌入的分类损失。论文没有把这三部分设计得多复杂,复杂的是如何让它们在同一轮训练里互不拖后腿。下面我把每个损失都拆开讲一下。

3.1 三个损失函数分别是干什么的

中心点热图使用的是带惩罚因子的 Focal Loss 变体。因为在一张图上,绝大多数位置都是背景,只有少数几个中心点是前景,正负样本极不平衡。Focal Loss 会让模型重点学习那些难分的前景点,同时不让大量负样本把损失带偏。

边界框尺寸用的是 L1 Loss,直接在中心点回归目标宽高。这里要注意,现在很多心血来潮实现的代码会和 CenterNet 一样把中心偏移也一起回归,FairMOT 的公开实现一般也保留了偏移预测。偏移量虽然看起来不大,但在中心点落到特征图分数坐标时很关键,它对边界框整体回归精度有提升。

Re-ID 嵌入训练用的是 softmax 分类损失。做法是把训练集中所有目标 ID 当成类别,让嵌入向量经过一个全连接层分类。目标中心的 GT 位置会生成一个标签,网络需要把这些位置编码成足以区分不同身份的特征。论文中提到,在 GT 中心附近取一个 2×2 的邻域作为正样本参与 Re-ID 损失,这样可以缓解下采样导致的中心坐标偏移问题:GT 中心点经过 4 倍下采样后,不一定恰好落在整数像素上,让周围几个像素都学习同一个 ID,训练会更稳。

3.2 数据增强与训练策略

训练时,FairMOT 通常会把检测数据和 Re-ID 数据混在一起采样。检测数据标注的是每个人框和类别,Re-ID 数据标注的是每个人框和独立 ID,两边的标签形式其实可以统一成“中心点 + 宽高 + ID”。但合并时有一个隐藏的坑:不同数据集中 ID 编号全是各自从 0 开始的,直接拿来训练,就会让网络误以为两个数据集的 0 号是同一个人。所以训练前必须把所有目标的 ID 重新映射成全局唯一编号,这一步没做对,Re-ID 分支基本学不出来。

数据增强方面,随机翻转、随机缩放、随机裁剪、颜色抖动是标配。其中随机裁剪要特别注意:一个目标被裁掉一半后,中心点可能被切出画面,这种样本在生成热图和 Re-ID 标签时需要过滤掉,否则会给网络喂非常矛盾的标签。论文作者在增强上并没有引入特别花哨的模块,但围绕“中心点必须还在画面内”这一条做了很多细节限制,这一点非常值得复现时留意。

3.3 输出分辨率对训练的直接影响

我在复现时对 stride 这个参数体会特别深。如果把 stride 改成 8,小目标在特征图上的正样本点变少,热图训练会相对稳定,因为背景点少了;但 Re-ID 的嵌入区域也变小,2×2 邻域采样经常采到目标边缘,特征代表性急剧下降。改成 stride 4 后,检测分支依旧稳定,Re-ID 分支得到的信息量却成倍增加,IDF1 在密集场景能明显看到提升。

所以 FairMOT 里的“公平性”不只体现在锚框采样上,还体现在特征分辨率这个容易被忽略的维度。论文用实验说明,低分辨率特征图严重伤害 Re-ID 分支,这就是为什么很多检测模型直接加一个 Re-ID 头效果并不好:检测网络为了速度和语义,习惯把特征压到很低的分辨率,但身份特征恰恰需要足够细的空间信息。

4. 推理与数据关联:让跟踪器在线跑起来

模型训练完成后,推理阶段要解决一个核心问题:有了当前帧的检测框和每个框的嵌入向量,怎么把它们和已有的轨迹关联起来?FairMOT 的推理流程非常清晰,几乎把重点全压在“外观距离”这一个维度上,不做运动预测,也不依赖复杂的轨迹管理,简洁但有代价。

4.1 检测结果筛选与嵌入提取

输入一张图像,经过网络后得到热图、宽高、偏移和嵌入图。首先对热图做一个 3×3 的最大值池化,这一步的作用是找到局部峰值点。只有那些既是局部最大值、又大于检测阈值的点,才会被当作目标中心。然后按置信度从高到低排序,保留前 K 个中心点作为该帧的检测结果。

拿到中心点坐标后,先用它加上偏移修正得到精确位置,再从嵌入图里取出对应位置的 128 维向量,同时用宽高输出恢复出边界框。整个过程没有 NMS,因为每个目标只会有一个中心峰值点,候选框之间天然不重叠。这个设计让时序上的特征提取变得很简单:上一帧和这一帧,只要中心点还在,拿到的特征大概率属于同一个特征空间,不会因为 NMS 阈值漂移而突变。

不少人会忽略一个经验点:检测阈值不要调太高。阈值太高虽然会减少误检,但会把一些低置信度但真实存在的目标挡住,尤其在拥挤场景,这些目标往往正是最容易断 ID 的目标。Better 的做法是保留较高的候选数,把过滤动作交给后面的距离阈值去完成。

4.2 基于距离度量的数据关联

FairMOT 的数据关联用的是逐帧在线匹配。对每个已有轨迹,维护一个最近的嵌入向量列表,一般会取最近若干帧的平均值;新帧到来后,把每个检测的嵌入向量和每个轨迹的平均嵌入向量做余弦相似度计算。相似度越高,说明两者是同一目标的可能性越大。

然后把这个相似度矩阵转化为距离矩阵,丢给匈牙利算法求全局最优匹配。匈牙利算法在这里解决的是“谁匹配谁不冲突”的分配问题,避免两个人同时争同一个检测框。匹配完成后,没有被匹配上的既有轨迹进入“丢失”状态,如果连续丢失超过阈值 T 帧,就从轨迹集合中删除;没有被匹配上的新检测则新建轨迹。

伪代码大概是这个流程:

# 伪代码:在线关联流程 for frame in frames: heatmap, size, offset, embedding_map = model(frame) dets = peak_non_max_suppression(heatmap, top_k) # 对每个检测提取中心点嵌入 for det in dets: det.embedding = embedding_map[det.center_y, det.center_x] # 计算轨迹与检测之间的距离矩阵 cost_matrix = compute_cosine_distance( [track.avg_embedding for track in tracks], [det.embedding for det in dets] ) matches, unmatched_tracks, unmatched_dets = hungarian_matching(cost_matrix) for track_idx, det_idx in matches: if cost_matrix[track_idx, det_idx] < distance_threshold: tracks[track_idx].update(dets[det_idx]) else: unmatched_dets.append(dets[det_idx]) unmatched_tracks.append(tracks[track_idx]) for idx in unmatched_tracks: if tracks[idx].lost_frames > max_lost: delete_track(tracks[idx]) for idx in unmatched_dets: create_new_track(dets[idx])

4.3 几个关键超参数的实际影响

FairMOT 对外观距离阈值很敏感。常见实现里,阈值取 0.2 到 0.4 之间比较合理,但这个数一定要按实际场景重调。阈值太严,目标稍微换个角度、换个光照就会被判定为新轨迹;阈值太松,两个相似外观的行人很容易发生身份交换。我个人经验是:先跑一段典型视频,把匹配失败的错误案例打印出来,统计一下正确匹配和错误匹配的余弦距离分布,再决定阈值落在哪。

嵌入队列长度也值得调。只保留上一帧的嵌入,抖动会比较大;保留几十帧的嵌入取平均,可以把姿态变化和短暂遮挡造成的临时偏差抹掉,但队列太长也会引入过时外观,导致重识别滞后。一般取 10 到 30 帧之间比较稳。丢失轨迹的容忍帧数 max_lost 需要和视频帧率挂钩,20 帧的视频和 30 帧的视频,同一个遮挡时长对应的帧数完全不同。

5. 实验结果与对比分析:它到底改进了什么?

FairMOT 在论文里和多个当时的联合检测与跟踪方法做了对比。这部分的结论对我来说比具体榜单数字更有启发:它不是在 MOTA 上狂飙突进,而是把 IDF1 和 ID Switch 改善得很明显。简单说,FairMOT 没有把检测做得碾压别人,但它把“身份保持”这件事做得非常稳。

5.1 定量指标与基线的差距

在标准 MOT 测试集上,FairMOT 的 MOTA 相比同时期的 JDE 基线提升不算夸张,但 IDF1 提高了好几个点,ID Switch 数量则显著下降。IDF1 提高,说明同一个 ID 覆盖的轨迹长度更完整;ID Switch 下降,说明身份跳变少了。这组结果非常符合它的设计目标:用无锚点中心点采样和更高分辨率特征,换来更稳定的外观嵌入。

如果你去复现并跑自己的监控视频,最直观的感受可能不是检测框变准了,而是目标被遮挡后,重新露出来时还能沿用自己的 ID。这个体验上的提升,比 MOTA 那零点几个点的变化要明显得多。所以评估一个跟踪器,不能只看排名,要看它在遮挡、拥挤、小目标这些具体难点上的行为。

5.2 为什么比基于锚框的方法稳定

原因可以归纳成三条。第一条是特征采样位置更干净。基于锚框的方法从框区域抠特征,框内经常混进背景和其他目标;FairMOT 从中心点的嵌入图取特征,等于硬性要求网络在目标的正中心学习身份判别,干扰像素天然更少。

第二条是特征分辨率更高。许多基于锚框的检测器为了追求速度,把输出 stride 做得很高,小目标在高层特征图上的空间信息所剩无几。FairMOT 把 stride 拉到 4,小目标的特征从“看不见”变成“看得见”,Re-ID 分支也就有了发挥空间。

第三条是多任务梯度更均衡。锚框检测器里锚框的正负样本比例严重失衡,检测分支的梯度很容易压过 Re-ID;而无锚点方法下,检测分支关注的是稀疏的中心热图,Re-ID 分支关注的是这些中心点上的语义分类,二者都只在目标点附近产生强梯度,整体上更容易平衡。

5.3 从实验里能提炼出的方法论

论文里做了不少消融,归一化下来就是一个原则:多任务共享网络,先要检查两个任务对特征的“空间偏好”是否一致。检测任务喜欢能看到完整前景区域的特征,Re-ID 任务喜欢能看到目标细节和高分辨率空间信息的特征。如果两个任务对分辨率的需求不一致,强行共享一个低分辨率特征图,弱势任务一定吃亏。

这个原则放到今天的很多多任务模型里依然成立。很多人把跟踪效果不好归因于 Re-ID 分支不够深、损失不够大,但经常忽略最基础的 feature stride 和采样位置问题。FairMOT 用一堆简单设计解决了这类问题,我认为这是它最有价值的地方。

6. 从论文到实战:复现要点与避坑心得

FairMOT 的公开实现其实非常接近论文描述,但真正自己从零复现一遍,会发现不少论文没写透、但实际训练和部署时躲不掉的问题。这一段我把自己遇到过的坑和觉得有用的调参经验整理出来。

6.1 复现时的常见问题速查

问题现象可能原因建议处理方式
训练时 loss 下降正常,但 IDF1 很低Re-ID 分支有效信息不足,或 ID 映射未全局统一检查训练数据 ID 是否从 0 重置,改成全局唯一 ID
检测结果正常,但嵌入特征几乎全是同一个向量Re-ID 损失权重太小或学习率设置不当适当增大 Re-ID 分支的梯度,实时打印嵌入相似度矩阵
小目标经常断 ID输出 stride 太大或输入分辨率过低确认 stride 为 4,尽量提高输入分辨率
遮挡后重新出现时 ID 全变距离阈值太严格调低距离阈值,增加嵌入队列长度
显存不够高分辨率和 batch size 太大先降 batch size,保留 stride 4,优先保证小目标特征质量

第一个坑是我觉得最容易踩的。很多人从不同数据集拉数据,ID 全是各自从 0 开始编号,直接拼到一起训练。模型一看,这个人的 ID 是 0,那个人的 ID 也是 0,它就会很迷惑:这两个人到底是不是同一个?结果 Re-ID 完全学不好,表现为嵌入向量区分度极差。这个问题在官方实现的默认脚本里往往已经处理好,但你自己换数据集时特别容易漏。

6.2 我实际调参和测试中的几点经验

第一,务必把失败案例可视化出来。只盯着 MOTA 和 IDF1 看,很难定位问题到底出在检测还是关联。我会挑一个遮挡频繁的视频,把每一帧每个目标的余弦距离矩阵打印出来,和人工标注的真实匹配关系对比一下,马上就能看出来距离阈值该往哪个方向调。

第二,FairMOT 原本不加运动模型,这在低帧率视频里会很吃亏。视频帧率低的时候,目标两帧之间位移很大,外观变化也大,纯靠余弦距离很容易断。我在实际项目中会加一个轻量的运动一致性检查:外观距离作为主匹配依据,运动预测只用来拒绝明显不合理的匹配,比如上一帧在画面左边、这一帧突然跳到右边,除非外观极度相似,否则直接拒绝。这样既保留了 FairMOT 的简洁性,又能挽回不少 ID Switch。

第三,嵌入维度 128 在绝大多数场景下够用,但密集人群场景可以试 256。更高的维度能容纳更多身份信息,不过训练数据不够时也更容易过拟合。我的习惯是先跑 128 维作为基线,如果密集场景里相似外观目标总被搞混,再用 256 维重训一次,对比训练集 loss 和公开测试集指标,确认是不是过拟合。

6.3 后续可以怎么扩展

FairMOT 之后,很多人沿着两条路改进。一条是把跨帧信息显式引入网络,比如在当前帧的特征之上融合上一帧的轨迹特征或注意力权重,让检测分支在遮挡时也能根据时序线索找回目标。另一条是改进轨迹管理,比如把丢失轨迹的晚年判断做得更合理,或者用街头匹配代替单帧匹配,降低瞬时外观突变的影响。

我觉得对学习的人来说,FairMOT 更大的价值是提供一个“度量公平性”的思考框架。任何多任务网络,你都可以问三个问题:两个任务需要的特征分辨率是否一致?两个任务的采样位置是否冲突?两个任务的损失量级和梯度是否失衡?把这些问题回答完,很多方案取舍就自然浮出水面了。

如果让我给准备入坑多目标跟踪的人排个顺序,我会说:先读懂 FairMOT 里的“中心点采样 + 高分辨率嵌入”这个思路,再动手复现一遍,最后才谈在上面加模块做创新。每次拿到一个新场景,也建议用它的训练逻辑先跑一个稳定基线,再根据可视化结果做有针对性的修改。不要直接抄一个公开超参数就上生产,跟踪器的阈值、队列长度、丢失容忍帧数这些,和你的相机角度、帧率、人群密度强相关。把这条路走通一遍之后,你再看那些号称“更强”的追踪网络,基本都能一眼看出它们到底改在检测、改在嵌入,还是改在关联策略上了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询