市中心的春熙停车场里,老王当了几十年协管员。过去他的绝活,是怀里揣着一沓厚厚的“模板卡”——卡片按车的长短、胖瘦裁成几十种规格。每来一辆车,他就举起卡片,一张张往车上比画:这张太窄,换那张;那张太长,再换一张方的……一天下来,几百张卡片在兜里进进出出上千回,能真正套中的却没几张。 后来老王换了个思路。他不再掏卡片,而是爬上瞭望台,眯着眼从高处往下看:“那辆车,中心就在 3 号立柱旁边,车长约 5 米,宽约 1.9 米。”不试模板,直接报出位置和大小,一报一个准。 老王的这套新本事,就是这篇要讲的主角——无锚框目标检测。咱们把它拆开看:传统的“模板卡”为什么吃力不讨好;“直接定位”又是怎么认出目标中心、量出目标尺寸的;这套思路从哪来、强在哪、如今用在哪。读完之后你再回头看摄像头画面,就能看懂算法是怎么“一眼圈出”每一辆车、每一个人了。

岗位关联

学懂 Anchor-free,你就能理解目标检测从“预设先验框”走向“端到端直接回归”的技术趋势,在工程选型(速度/精度/超参成本)时做出更专业的判断,这是 CenterNet、FCOS 等现代检测模型的核心底座。

目录
  1. 可视化演示
  2. 锚框机制
  3. 设计动机
  4. 无锚框总览
  5. 角点检测
  6. 中心点检测
  7. 优势分析
  8. 发展脉络
  9. 落地应用
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

通过Anchor-based锚框匹配局限、FCOS逐像素预测、CenterNet中心点热力图三个模式,展示Anchor-free方法如何消除预设锚框实现更简洁高效的目标检测。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Anchor-based方法的固有局限 每个位置预设9个锚框3种尺度3种长宽比需大量超参数调优 IoU匹配阈值敏感小目标匹配困难正负样本极度不均衡 Anchors = positions × scales × ratios → IoU matching 锚框设计复杂且对新场景需重新统计分析

锚框机制

老王的模板卡可不是随便裁的。他在裁卡前会先做统计:这个车场常见的是轿车、SUV、小货车,所以卡片被分成 6 种长度、4 种宽度,一共 24 种规格,每种规格印一批,全部揣进兜里。“车场会停什么车,卡片就有什么规格”——这张卡,就是目标检测里鼎鼎大名的锚框(Anchor)。

把镜头从老王身上拉开,换成卷积网络看一张图:它先把图片层层浓缩成一张更小、更抽象的特征图,好比老王站到瞭望台看到的“缩小版车场”。传统检测器在这张特征图的每个格子上,都铺上预先设计好的若干个锚框——每个锚框对应一种预设的尺寸和长宽比。图片里目标有多大、比例是横是竖,全都提前被“猜”成了这批固定模板。

铺完之后,怎么判断哪个锚框算“套中”了车?业界用交并比(IoU)来丈量:把锚框和真实框当成两块区域,算它们重叠面积占合并面积的比重。

老王每天最头疼的,恰恰是“套没套中”的裁决——有的卡只盖住车头,有的卡罩住了半条车道。IoU 就是那个铁面无私的裁判:重合率达标才算套中。卡片虽多,真正能派上用场的,永远是极少数。

IoU(A,B)=∣A∩B∣∣A∪B∣\displaystyle \text{IoU}(A, B) = \frac{|A \cap B|}{|A \cup B|}
IoU 衡量“模板卡”和“真实车体”贴得有多紧,数值越接近 1 套得越准;大于 0.5 通常判为正样本,负责“这里有目标”的预测,再回归修正位置与大小。
  1. 集合 A 与 B把锚框看作一块区域 A,真实目标看作另一块区域 B——对应老王手里的模板卡和真实车体。
    A: 锚框区域,B: 真实框区域A:\ \text{锚框区域},\quad B:\ \text{真实框区域}
  2. 交集 |A∩B|两片区域重叠的部分,面积越大,说明卡片盖住车身越多。
    ∣A∩B∣=重叠面积|A \cap B| = \text{重叠面积}
  3. 并集 |A∪B|两片区域合并后覆盖的总面积,重叠部分只算一次。
    ∣A∪B∣=SA+SB−∣A∩B∣|A \cup B| = S_A + S_B - |A \cap B|
  4. 比值即 IoU重叠占比越高贴得越好,IoU 常以 0.5 为阈值划分正负样本。
    IoU∈[0,1],越接近 1 越贴合\text{IoU} \in [0, 1],\quad \text{越接近 1 越贴合}

设计动机

日子久了,老王腰酸背痛:一晚上两百辆车,平均每辆要试 50 张卡,其中 49 张连车的边都不沾。“我九成九的力气,都花在了翻没用的卡上。”这个抱怨,和学术界抛弃锚框的心路历程一模一样。

一张普通照片里常常只有几十个目标,而锚框法会在特征图每个位置铺好几个框,一张图轻松生成上万甚至几十万个候选框。于是绝大多数锚框面对的是空白背景——这就是著名的正负样本失衡。

失衡带来连锁反应:训练时模型被海量“没有目标”的例子淹没,要么学不到东西,要么被带偏,于是又得发明难例挖掘、Focal Loss 这类“补药”。更麻烦的是,锚框的尺寸和长宽比需要针对每个数据集手工设计——换成一批新数据(比如从汽车换成轮船),又得重调一遍。两阶段流程还要先生成候选区域、再分类回归,环节多,误差还会层层累积。

老王终于把整沓模板卡摔在桌上:问题不在他手笨,而在“预先定死的模板”这件事本身。与其用 99% 的力气做无用功,不如换一套不依赖模板的打法——这正是 Anchor-free 登场的理由。

rneg=1−NposNall≈99.9%\displaystyle r_{\text{neg}} = 1 - \frac{N_{\text{pos}}}{N_{\text{all}}} \approx 99.9\%
一张图上的锚框总数里,真正“套中”目标的正样本少得可怜,负样本占比逼近 99.9%,意味着绝大部分计算都在做无用功。
  1. 总框数 N_all一张图生成的全部候选框总数,包含正负样本。
    Nall=Npos+NnegN_{\text{all}} = N_{\text{pos}} + N_{\text{neg}}
  2. 正样本 N_pos与真实目标 IoU 超过阈值、真正“套中”的锚框。
    Npos=与真实框 IoU>0.5 的锚框个数N_{\text{pos}} = \text{与真实框 } \text{IoU} > 0.5 \text{ 的锚框个数}
  3. 负样本占比总量减去正样本,再除以总量,就是被白白浪费的比例。
    rneg=Nall−NposNall=1−NposNallr_{\text{neg}} = \frac{N_{\text{all}} - N_{\text{pos}}}{N_{\text{all}}} = 1 - \frac{N_{\text{pos}}}{N_{\text{all}}}
  4. ≈99.9%几万锚框对几十个目标,负样本占比往往高达 99% 以上。
    rneg≈99.9%r_{\text{neg}} \approx 99.9\%

无锚框总览

老王的崭新思路,是彻底扔掉卡片,在瞭望台上把整个车场当成一张大坐标图。他不再关心“车像哪张卡”,而是让每一个网格自己回答两个问题:“我这格有没有车?”以及“如果有,车的中心离我多远、车有多大?”

这个思路落到神经网络里,就是“密集预测”:检测器不再先生成一批候选框,而是对特征图上的每一个位置,直接输出一个向量——前半段是它属于各个类别的置信度,后半段是目标的几何信息(中心的偏移量、宽、高)。

这个“每个点自报家门”的设计,只是无锚框思想的总纲。具体怎么做几何部分的回归,江湖上分了两派:一派盯着目标的“角”,比如 CornerNet 找左上、右下两个角点;另一派盯着目标的“心”,比如 CenterNet 找中心点。后文两节,咱们分别跟着老王走一遍。

out(i,j)=[ p1, p2, …, pC⏟类别置信, Δx, Δy, w, h⏟几何量 ]\displaystyle \text{out}(i,j) = \bigl[\, \underbrace{p_1,\ p_2,\ \dots,\ p_C}_{\text{类别置信}},\ \underbrace{\Delta x,\ \Delta y,\ w,\ h}_{\text{几何量}} \,\bigr]
特征图每个格子都自报家门:一类是“我像不像车/人”,另一类是“目标中心和大小怎么算”,两者合起来,一个前向就能得到检测结果。
  1. 位置 (i,j)特征图上的任意一个网格,相当于车位地图上的一个坐标。
    (i,j)∈{1,…,H}×{1,…,W}(i, j) \in \{1,\dots,H\} \times \{1,\dots,W\}
  2. 类别置信 p_c该位置属于第 c 类目标的概率,c = 1…C。
    pc=Pr⁡(类别 c∣位置 (i,j))p_c = \Pr(\text{类别 } c \mid \text{位置 } (i,j))
  3. 几何量回归中心相对该网格的偏移 Δx、Δy,以及目标宽 w、高 h。
    Δx, Δy, w, h\Delta x,\ \Delta y,\ w,\ h
  4. 端到端解码训练时用标注监督这些值,推理时直接从向量解码出框。
    Detection=Decode(out(i,j))\text{Detection} = \text{Decode}\bigl(\text{out}(i,j)\bigr)

角点检测

老王摸索出一个省力窍门:既然一辆车要被框住,那框的左上角和右下角就是最好认的两个点——像车头和车尾的两个角灯。只要同时认出这两个角,把两点一连,车的包围框就画出来了。

CornerNet 就是这么干的。它不再回归“框本身”,而是让网络输出两张热力图:一张标出“哪儿是左上角”,一张标出“哪儿是右下角”。每张热力图上越亮的地方,代表网络越确信这里有一个角点。但“有两个角”还不够,得知道哪两个角属于同一辆车——CornerNet 额外为每个角点预测一个嵌入向量(embedding),训练时让同一辆车的两个角向量互相靠近,不同车辆的向量彼此远离,从而把左角、右角“配对”成一家人。

拿到左上角 $(x_1, y_1)$ 和右下角 $(x_2, y_2)$ 之后,目标框 B 由 min/max 运算直接拼出:

找角点时还有个细节:判断一个点是不是左上角,得参考它右边和下边的信息,于是 CornerNet 设计了角点池化,把该点右侧、下侧区域的最大值汇聚过来,让左上角“看得见”物体的轮廓。老王这招的代价是:两辆车紧挨着停时,左角和右角容易认串。嵌入向量就像他在每个角上贴了半张票据,只有票据对得上号的角才能凑成一辆车。角的组合多了,配对也就成了新的负担——这为后来的“中心点”思路埋下了伏笔。

B=(min⁡(x1,x2), min⁡(y1,y2), max⁡(x1,x2), max⁡(y1,y2))\displaystyle B = \bigl( \min(x_1,x_2),\ \min(y_1,y_2),\ \max(x_1,x_2),\ \max(y_1,y_2) \bigr)
两个角点一个在左上、一个在右下,分别取最小和最大,就能把一整条框“撑”出来。找角点时还用到角点池化,让角点“看得见”物体的边。
  1. 左上角 (x1,y1)目标是左上角点,x1 和 y1 是它的两个坐标,来自左上角热力图的峰值。
    (x1,y1)∼左上角热力图峰值(x_1, y_1) \sim \text{左上角热力图峰值}
  2. 右下角 (x2,y2)右下角点和它对称,来自右下角热力图。
    (x2,y2)∼右下角热力图峰值(x_2, y_2) \sim \text{右下角热力图峰值}
  3. 取最小补齐左与上min 运算保证左边取更靠左的坐标、上边取更靠上的坐标。
    x左=min⁡(x1,x2),y上=min⁡(y1,y2)x_{\text{左}} = \min(x_1, x_2),\quad y_{\text{上}} = \min(y_1, y_2)
  4. 取最大补齐右与下max 运算把框的右下边界补齐,两角点被“撑”成完整矩形。
    x右=max⁡(x1,x2),y下=max⁡(y1,y2)x_{\text{右}} = \max(x_1, x_2),\quad y_{\text{下}} = \max(y_1, y_2)

中心点检测

老王进一步做减法:既然认角还要配对、像拼拼图,干脆只认一个点——车的正中心。中心认准了,再估个宽和高,框自然出来。这一下,配对问题消失了。

CenterNet 用一张类别热力图来“找中心”:网络在特征图的每个位置输出“这里离某个目标的中心有多近”的分数,数值越大越可能是中心,并且用高斯核把每个真实中心点“抹”成一个亮斑,让网络学起来更平滑。检测时,后处理只做一件事:用 3×3 的最大池化扫过热力图,凡是比周围 8 个邻居都亮的位置,就是一个局部峰值,取前 K 个峰值作为预测的中心——这一步替代了传统 NMS。

峰值得到中心点 $(c_x, c_y)$,再配合网络回归的宽 w 和高 h,包围框从中心向四周展开:

老王在瞭望台上看得越远,越难看清细节——特征图的网格就好比他的视力分辨率。他于是多报一句“我看偏了大概半格”(offset),把模糊补回来。中心点 + 偏移 + 宽高,三样凑齐,一帧画面里的所有车,就这么被“一眼”全圈了出来。

B=(cx−w2, cy−h2, cx+w2, cy+h2)\displaystyle B = \Bigl( c_x - \frac{w}{2},\ c_y - \frac{h}{2},\ c_x + \frac{w}{2},\ c_y + \frac{h}{2} \Bigr)
中心点向左、右各展开半个宽度,向上、下各展开半个高度,一个框就画好了。因为特征图比原图小(缩小了 stride 倍),CenterNet 还额外预测一个中心偏移(offset),把坐标“扶正”到亚像素精度。
  1. 中心点 (cx,cy)来自热力图峰值,经 3×3 最大池化筛选后还原的位置。
    (cx,cy)=峰值点×s+offset(c_x, c_y) = \text{峰值点} \times s + \text{offset}
  2. 半宽 w/2从中心向左、向右各展开一半宽度。
    w2\frac{w}{2}
  3. 半高 h/2从中心向上、向下各展开一半高度。
    h2\frac{h}{2}
  4. 解码成四角坐标中心减半宽/半高得左上角,加半宽/半高得右下角。
    B=(cx−w2, cy−h2, cx+w2, cy+h2)B = \left(c_x - \frac{w}{2},\ c_y - \frac{h}{2},\ c_x + \frac{w}{2},\ c_y + \frac{h}{2}\right)

优势分析

把新老办法放在一起算账,老王乐了:以前翻卡片,每辆车要对几百上千张模板;现在只需盯着中心点一个位置,再把尺寸量出来。

算一笔账就清楚了。一张特征图有 H×W 个位置,锚框法每个位置要铺 K 种尺度、R 种长宽比的框:

优势可以列成四条:一是超参少了,不再为“锚框多大、什么比例”而调参;二是流程短了,训练时不用再做锚框匹配分配正负样本,模型更接近“输入图片、输出框”的端到端;三是正样本比例提高了,无数“空模板”不再参与计算,训练更稳;四是后处理轻了,CenterNet 这类方法用峰值提取代替复杂的 NMS 流水线,部署时省时省力。当然老王也明白,“省力”不等于“躺着赢”:他仍需调模型的深度、看台高度(网络结构和下采样倍率)。但相比过去被模板卡绑住手脚,Anchor-free 把工程师从“调锚框”里解放了出来,把精力真正还给数据与网络设计。

Nanchors=H×W×K尺度×R比例\displaystyle N_{\text{anchors}} = H \times W \times K_{\text{尺度}} \times R_{\text{比例}}
锚框总数随“位置 × 尺度 × 比例”爆炸式增长;而 Anchor-free 只需要关心 H×W 个位置点本身,候选数量断崖式下降。
  1. 位置总数 H×W特征图被划分成 H 行 W 列网格,每个网格一个位置。
    N位置=H×WN_{\text{位置}} = H \times W
  2. 尺度数 K每个位置要试 K 种不同大小。
    K=预设尺度数K = \text{预设尺度数}
  3. 比例数 R每种尺度还要再试 R 种长宽比。
    R=预设宽高比数R = \text{预设宽高比数}
  4. 总数爆炸锚框总数是三者乘积,而 Anchor-free 只保留第一步的 H×W。
    Nanchors=H×W×K×RN_{\text{anchors}} = H \times W \times K \times R

发展脉络

老王的手艺不是一天练成的。回看这些年,他的“无模板”之路经历了四步:先有人试过不贴卡片,再有人学会认角,又有人简化成认心,最后有人把“直接定位”推向了极致。

2015 年 DenseBox 最早在密集位置逐像素回归人脸框,是 Anchor-free 的先声;2018 年 CornerNet 把检测改造成“角点检测 + 配对”,第一次在 COCO 榜单上比肩两阶段方法,证明不靠锚框也能打;2019 年 CenterNet 用中心点取代角点配对,又快又稳;同年的 FCOS 换了一种全然不同的刻画方式——对每个像素直接回归它到目标框四条边的距离,并借助特征金字塔(FPN)在不同尺度上各自负责,让逐像素回归也能应对大小悬殊的目标。

但像素离目标中心越远,回归出的四边距离越不可信。FCOS 于是新增一个 centerness(中心度)分支,给每个位置打一个“我离中心多近”的分:越靠中心越接近 1,越靠边缘越接近 0,然后用它给该位置的框打分打折。

这条脉络,就是老王一路做减法的过程:去模板、去配对、去多余的后处理。从“满场试卡”到“直取中心”,Anchor-free 用事实证明:目标检测的“招数”越少,反而越接近问题的本质——先定位,再量尺寸。

C∗=min⁡(l∗,r∗)max⁡(l∗,r∗)×min⁡(t∗,b∗)max⁡(t∗,b∗)\displaystyle C^{*} = \sqrt{ \frac{\min(l^{*}, r^{*})}{\max(l^{*}, r^{*})} \times \frac{\min(t^{*}, b^{*})}{\max(t^{*}, b^{*})} }
中心度只看一件事:这个像素是不是“正对”目标中心。左右距离、上下距离的比值相乘再开方,中心处为 1,越靠边越接近 0,低质量框天然被压低。
  1. 四边距离 l,r,t,b像素到目标框左、右、上、下四条边的距离,由回归分支输出。
    l∗, r∗, t∗, b∗l^{*},\ r^{*},\ t^{*},\ b^{*}
  2. 左右比值左右距离的较小者除以较大者,中心处为 1,越靠边越接近 0。
    min⁡(l∗,r∗)max⁡(l∗,r∗)\frac{\min(l^{*}, r^{*})}{\max(l^{*}, r^{*})}
  3. 上下比值上下距离也做同样的运算。
    min⁡(t∗,b∗)max⁡(t∗,b∗)\frac{\min(t^{*}, b^{*})}{\max(t^{*}, b^{*})}
  4. 相乘开根号两个比值相乘再开方,得到 0 到 1 的中心度,给该位置的检测框打分。
    C∗=min⁡(l∗,r∗)max⁡(l∗,r∗)×min⁡(t∗,b∗)max⁡(t∗,b∗)C^{*} = \sqrt{\frac{\min(l^{*}, r^{*})}{\max(l^{*}, r^{*})} \times \frac{\min(t^{*}, b^{*})}{\max(t^{*}, b^{*})}}

落地应用

老王退休后,他这套“无模板定位”的思路被移植到了很多比停车场更复杂的场景。只要“找目标 + 量大小”这个套路成立,Anchor-free 就能派上用场。

自动驾驶里,前视摄像头要在几十毫秒内同时圈出车、行人、骑行者,目标大小比例千变万化,锚框法要设计多套模板,Anchor-free 的中心点 + 宽高回归则天然省事;工业质检里,产品表面的划痕、凹坑形状随机,Anchor-free 对“没见过的缺陷”也容易给出响应;遥感图像里,船、飞机密密麻麻,峰值提取天然适配“每个峰对应一个目标”的密集场景。

如何衡量在某个场景里好不好用?学术界常用平均精度均值(mean Average Precision, mAP)——对每个类别算一条精度-召回曲线下的面积 AP,再对所有类别取平均:

mAP 高了,说明老王这套“先认中心、再量尺寸”的平均水准高;但具体到每个停车场,停车线划多密、车位朝向如何,仍要因地制宜地调网络。工具变了,“读懂场景”这件事,永远得靠算法工程师自己。

mAP=1C∑k=1CAPk\displaystyle \text{mAP} = \frac{1}{C} \sum_{k=1}^{C} \text{AP}_k
mAP 把“车、人、缺陷”等所有类别的检测精度平均起来,得到一个 0 到 100% 的综合指标,方便不同模型在同一个数据集上直接对比。
  1. 每个类别一个 AP对每一类分别画精度-召回曲线并求曲线下的面积。
    APk=∫01Pk(Rk) dRk\text{AP}_k = \int_0^1 P_k(R_k)\, dR_k
  2. C 个类别求和把各类 AP 累加,反映所有类别的整体水平。
    ∑k=1CAPk\sum_{k=1}^{C} \text{AP}_k
  3. 取平均得到 mAP除以类别数,得到一个综合精度指标。
    mAP=1C∑k=1CAPk\text{mAP} = \frac{1}{C} \sum_{k=1}^{C} \text{AP}_k

AI 应用场景

自动驾驶实时感知

阶段:模型推理与部署

解决的问题:传统锚框法在车载芯片上要逐框评估数千个锚框,计算与显存压力大,且路上车辆、行人的大小比例多变,手工设计的锚框容易失配;Anchor-free 直接预测中心点加宽高,省去锚框分配和大量负样本计算,更适合 30 毫秒内出结果的实时管线。

具体案例:某自动驾驶公司在车规级芯片上部署 CenterNet 检测行人与车辆:输入 512×512 图像,backbone 用轻量 DLA-34,峰值提取只取前 100 个中心点。相比同类 anchor-based 单阶段模型,端到端时延从 45ms 降到 28ms,且白天、夜间场景切换时无需重新设计锚框比例。

工业表面缺陷检测

阶段:数据标注与训练策略

解决的问题:产品表面缺陷(划痕、凹坑、污渍)的大小和形状随机,锚框的尺寸/比例先验难以覆盖;Anchor-free 让模型对“没见过的新缺陷”也有响应,降低换产线时重新调锚框的成本。

具体案例:某面板厂用 FCOS 检测 LCD 屏幕缺陷:FPN 三层输出加 centerness 低质量框抑制,把漏检率从锚框方案的 2.1% 压到 1.3%;新增缺陷类型只需补充标注,无需改网络结构,训练流程明显缩短。

Python 演示

python36 行
import numpy as np  def max_pool(hmap, k=3):    """3x3 最大池化: 仅保留比周围相邻位置都大的峰值点."""    H, W = hmap.shape    out = np.full_like(hmap, -1e9)    hp = np.pad(hmap, k // 2, mode='constant', constant_values=-1e9)    for i in range(H):        for j in range(W):            out[i, j] = hp[i:i + k, j:j + k].max()    return out  def decode_boxes(hmap, wh, offset, stride=4, thresh=0.5):    """Anchor-free 解码: 热力峰 -> 中心点 -> 左上/右下角."""    hits = np.where((hmap >= max_pool(hmap)) & (hmap > thresh))    boxes = []    for y, x in zip(hits[0], hits[1]):        cx = (x + offset[0, y, x]) * stride        cy = (y + offset[1, y, x]) * stride        w, h = wh[0, y, x], wh[1, y, x]        boxes.append((cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2, hmap[y, x]))    return sorted(boxes, key=lambda b: -b[4])  if __name__ == '__main__':    hmap = np.zeros((16, 16))    hmap[4, 5] = 0.9    # 目标 A 的中心落在 (4, 5)    hmap[11, 11] = 0.8  # 目标 B 的中心落在 (11, 11)    wh = np.zeros((2, 16, 16))    wh[0, 4, 5], wh[1, 4, 5] = 12.0, 8.0    wh[0, 11, 11], wh[1, 11, 11] = 16.0, 6.0    offset = np.zeros((2, 16, 16))    for x1, y1, x2, y2, s in decode_boxes(hmap, wh, offset):        print('box=(%.1f, %.1f, %.1f, %.1f) score=%.2f' % (x1, y1, x2, y2, s))
目的:用纯 NumPy 模拟 CenterNet 式解码——从“热力图峰值”还原出目标框,演示 Anchor-free 免锚框的后处理全过程。
  1. hits = np.where((hmap >= max_pool(hmap)) & (hmap > thresh))峰值筛选:既是 3×3 邻域“最高点”,又超过置信阈值,才被当作目标中心。
  2. np.pad(hmap, k // 2, mode='constant', constant_values=-1e9)边界补极小值,让边缘像素也能正常做 3×3 池化。
  3. cx = (x + offset[0, y, x]) * stride中心坐标从特征图还原回原图:位置乘以步长,再加上预测的偏移修正。
  4. boxes.append((cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2, hmap[y, x]))由中心点向四周展开宽高一半,得到左上/右下角。
  5. for x1, y1, x2, y2, s in decode_boxes(hmap, wh, offset):主入口:模拟两张热力图,端到端打印出检测框。

常见误区

误区既然叫“无锚框”,那模型什么先验信息都不用,完全从零开始学,跟白纸一样。

正解“无锚框”去掉的只是“物体尺寸/比例的分布”这一手工先验,模型仍然保留 stride(下采样倍数)、多尺度特征、高斯核(把目标中心摊成一个峰)等结构假设。老王虽然没带模板卡,但“车一般停在车位内、中心在车体中间”这类常识还在脑子里——Anchor-free 去掉的是束缚,不是常识。

为何常见:"free"(无)字容易让人望文生义,以为模型完全零假设;其实 free 的对象特指 anchor 这项人工设计。

误区无锚框就没有重复框,后处理 NMS 可以整段删掉,一个不剩。

正解要看具体方法。CenterNet 用 3×3 最大池化提取峰,天然把每个目标压成唯一中心,确实省掉了传统 NMS;但 CornerNet 仍要合并角点候选,FCOS 也是“centerness 压低质量框 + 轻量 NMS”的组合。Anchor-free 更多是“减少/简化”后处理,而不是“后处理清零”,工程上仍需按模型验证。

为何常见:不少科普把 CenterNet 的“免 NMS”泛化成整个 Anchor-free 家族的特征;其实 NMS 只是被峰值提取这一算子替代或弱化。

误区新方法碾压老方法,换成 Anchor-free 我的指标一定上涨,不用再做对比实验。

正解精度上两者并无绝对输赢。Anchor-based(如 Faster R-CNN、仍用锚框设计的 YOLO 版本)在极小目标、极端宽高比目标、拥挤场景依然有竞争力;Anchor-free 的优势更多体现在实现简单、超参少、训练收敛稳定、部署友好。具体 mAP 高低取决于数据集分布、backbone 和训练策略,老王的新手艺更省力,不代表在每个停车场都必然赢。

为何常见:技术演进常被简化成“新必优于旧”,且论文榜单多为理想实验条件,掩盖了任务差异。

误区CenterNet 找到热力图最大值,这个点就是物体的精确中心,直接画框就行。

正解热力图是在 stride 下采样后的特征图上预测的,位置精度被限制在一个网格内(如 stride=4,误差最大 4 像素),直接当中心会导致小目标框偏差明显。CenterNet 额外回归一个中心偏移 offset(0~1 个网格内的亚像素修正),峰值点坐标 + 偏移 + 宽高三者合成才得到最终框。老王目测距离时说的“大概偏左半米”,就是 offset 的作用。

为何常见:人们习惯把热力图“最亮的位置”当作精确坐标,忽略了特征图分辨率被池化、卷积步步压缩的事实。

面试题

Q1. “Anchor-free“ 中的 ”free”(无)特指不依赖下列哪一项?

单选题 · easy

  • A.卷积神经网络的卷积核
  • B.预设尺寸比例的先验框← 正确答案
  • C.训练数据集的标注信息
  • D.特征金字塔的多层结构

答案:B。Anchor-free 抛弃的是手工设计的锚框(尺寸与长宽比先验),但卷积核、标注数据和特征金字塔它通通照用。就像老王扔掉了模板卡,可瞭望台和双眼还在。

Q2. CenterNet 的热力图峰值通常代表目标的什么信息?

单选题 · easy

  • A.目标类别数量的多少
  • B.目标中心所在的位置← 正确答案
  • C.目标左上角的方向
  • D.目标旋转角度的值

答案:B。CenterNet 把每个目标建模成中心处的一个高斯亮斑,热力图越亮代表越接近中心,峰值点就是目标的中心位置。认角是 CornerNet 的活儿,测旋转角不在 CenterNet 的设计里。

Q3. 下列哪些是 Anchor-free 代表性工作?

多选题 · easy

  • A.CornerNet 两角点法← 正确答案
  • B.CenterNet 中心点法← 正确答案
  • C.FCOS 逐像素回归← 正确答案
  • D.Faster R-CNN 区域建议

答案:ABC。CornerNet 用角点、CenterNet 用中心点、FCOS 用逐像素四边距离回归,都不需要预设锚框;Faster R-CNN 的 RPN 依赖大量锚框,属于 Anchor-based。就像老王的新手艺——不掏卡也能报出车位。

Q4. 采用“左上角 + 右下角两个关键点配对”思想的目标检测方法是?

单选题 · mid

  • A.CenterNet 中心点法
  • B.CornerNet 角点配对← 正确答案
  • C.DenseBox 密集人脸框
  • D.Faster R-CNN 候选区域

答案:B。CornerNet 预测两张热力图分别找左上角和右下角,再用嵌入向量把同一目标的两角配对;CenterNet 只看中心点,DenseBox 是早期逐像素回归,Faster R-CNN 是锚框两阶段方法。

Q5. 锚框法正负样本失衡的直接根源是?

单选题 · mid

  • A.锚框的总数远多于真实目标数← 正确答案
  • B.训练时图片的分辨率过低
  • C.卷积核尺寸设置得过大
  • D.损失函数只用了均方误差

答案:A。锚框法在特征图每个位置铺多个框,一张图上万个框,而真实目标只有几十个,绝大多数框落在背景上成为负样本。老王翻了几百张卡,真能套中的永远是少数——根源在于“卡太多、车太少”。

Q6. CenterNet 最终解码目标框时,需要哪三个量?

单选题 · mid

  • A.锚框长宽比、中心偏移、旋转角
  • B.热力峰值、中心偏移、宽高← 正确答案
  • C.左上角点、右下角点、类别数
  • D.区域建议、特征图、交并比

答案:B。CenterNet 用热力图峰值定位中心,offset 补偿下采样误差,宽高回归给出尺寸,三者合成包围框。它不需要锚框长宽比,也不需要配对两个角点。

Q7. 与传统锚框法相比,Anchor-free 的典型优势包括?

多选题 · mid

  • A.省去手工设计锚框尺寸比例← 正确答案
  • B.训练流程更简洁端到端← 正确答案
  • C.正负样本数量完全均衡
  • D.彻底告别所有后处理步骤

答案:AB。Anchor-free 最大的红利是不用调锚框、流程更短。但它并非绝对均衡,CenterNet 也有少量背景点;后处理上它简化而非消灭(如 FCOS 仍需轻量 NMS)。“完全”“彻底”这类绝对化表述通常都是错的。

Q8. CornerNet 通过什么机制把同一物体的两个角点准确配对?

单选题 · hard

  • A.角点池化编码空间位置
  • B.嵌入向量缩小同类距离← 正确答案
  • C.热力图阈值筛选峰值
  • D.特征金字塔多尺度融合

答案:B。CornerNet 为每个角点预测一个嵌入向量,训练让同一目标的两个角向量靠近、不同目标的角向量远离,推理时按向量距离配对。角点池化解决的是“角点看得到边界”,不是配对问题。

Q9. 关于 CenterNet 的描述,正确的有哪些?

多选题 · hard

  • A.用 3×3 最大池化提取热力峰← 正确答案
  • B.中心偏移补偿下采样误差← 正确答案
  • C.宽高回归输出目标框尺寸← 正确答案
  • D.必须先做候选区域生成

答案:ABC。CenterNet 后处理用最大池化筛峰,offset 修正在特征图网格上的量化误差,宽高分支给出框的尺寸,三管齐下得到最终框。它不需要 RPN 式的候选区域生成,这是 Anchor-free 的核心特征。

Q10. FCOS 引入 centerness 分支的主要目的是?

单选题 · extreme

  • A.加速卷积运算和显存占用
  • B.降低偏离中心框的质量权重← 正确答案
  • C.把回归目标改造成分类任务
  • D.增加锚框尺度和长宽比例

答案:B。逐像素回归时,离目标中心远的像素预测的框质量差,centerness 给每个位置打一个“离中心多近”的分,训练时用它给框的质量打折,推理时压掉边缘低质量框。它不改变运算量,也不属于锚框设计——就像老王更信任“正对着车头”的估测,而不是斜着瞟一眼的估测。