做人群计数的同行应该都有这种感觉:模型在稀疏场景下还算凑合,一旦换成演唱会散场、景区出入口、地铁换乘大厅这种人贴人的画面,预测人数就开始离谱,要么少报,要么把背景里的橱窗模特和灯箱广告也数进去。我最近在复盘一个思路——CVPR 2020 上关于注意力机制的 Attention Scaling for Crowd Counting 工作,它在当时重新定义了注意力在人群计数里的用法:不是简单把注意力图当 mask 去乘,而是把它当作一个缩放因子,去动态调整特征响应强度。这个细节看似不大,却在多个公开基准上让 MAE 降了一截,尤其在密集场景下收益非常明显。
这篇文章我想从任务本身的难点说起,把“为什么注意力能帮上忙”和“Attention Scaling 到底改了什么”讲透,再给出我实际复现和调参时踩过的坑。不管你是刚入门想做人群计数,还是已经跑过几个 baseline 想继续提升精度,都应该能从这里找到能直接用的东西。
1. 人群计数到底难在哪:不是数人头那么简单
1.1 任务定义与评价指标
人群计数(Crowd Counting)的目标是给定一张单目 RGB 图像,输出画面中的人数。这个任务最常见的做法不是直接回归一个数字,而是回归一张密度图(Density Map):每个像素点的值代表该局部区域的人群密度,整张密度图积分求和就是总人数。
采用密度图而不是直接回归数字的原因很实在:第一,它保留了空间分布信息,下游可以做人群热力分析、区域预警;第二,密度图上的监督信号是密集的,训练起来比单值回归稳定得多,不会出现“网络猜了个大致数字但位置全错”的情况。
评价指标方面,主流是用 MAE(平均绝对误差)和 MSE(均方误差):
- MAE = (1/N) Σ |预测人数 - 真实人数|,衡量整体偏差,业务上最关心这个。
- MSE = (1/N) Σ (预测人数 - 真实人数)²,放大了大误差样本的影响,对极端场景更敏感。
挑模型的时候不能只看 MAE,我见过不少模型 MAE 刷得很低,但一到密集区域就局部崩坏,MSE 惨不忍睹。落地时最好两个指标一起看,特别是做安全预警类业务,大误差样本才是真正要命的。
1.2 真实场景里的三大杀手
教科书上的测试集往往把问题简化了,但真实场景里的画面基本都是这三种情况的叠加:
透视尺度变化。同一个场景里,近处的人可能占据几百个像素,远处的人只有十几个像素。CNN 的感受野是固定的,同一个卷积核拿近处的特征去匹配远处的人头,天然就吃亏。传统做法是图像金字塔或多列网络,但这类方案计算量太大,而且不同尺度的特征融合方式很粗糙。
背景干扰。商场橱窗里的模特、海报上的人脸、电线杆顶部的装饰物、甚至树叶纹理,在高层语义特征里和真实人头的响应往往高度相似。没有注意力机制约束时,模型很容易把“看起来像头”的区域也激活。
密集遮挡。这个在拥挤场景里最头疼。一个人头可能只有 5×5 像素,还被前面的人挡住一大半。标注本身就困难,模型要学的是“从局部纹理推测人头存在”,而不是“看到完整头部轮廓才响应”。这种情况下,全局均匀的卷积特征表达力是不够的,必须让网络自己学会选择性关注那些“疑似人头但被遮挡”的区域。
我复现时最直观的感受是:在这三类问题上,普通 CNN baseline 的密度图总是“糊成一片”,而加了注意力缩放的模型密度图会锐利很多,头部中心有清晰的峰值,背景区域几乎无响应。这也是我后面会反复强调“注意力图可视化”的原因——它能告诉你模型到底在看什么。
2. 注意力机制为什么能救场:本质是信息路由
2.1 注意力在人群计数里的三种打开方式
注意力机制说白了就是让网络学会“把计算资源花在关键位置上”。人群计数场景里,常见的注意力有这几种:
空间注意力。生成一张和原图尺寸对应的权重图,告诉网络“哪些像素区域更像是人头区域”。这是最直观的,因为人群计数本质上是一个空间定位问题,空间注意力直接对应“在哪里数”的诉求。
通道注意力。特征图的每个通道可以理解成一种特征检测器,比如有的通道对头部边缘敏感,有的对肤色敏感。通道注意力用来决定“当前场景下哪些特征通道更重要”。这个在密集遮挡场景帮助也很大,因为局部纹理特征往往是分散在不同通道里的。
尺度注意力。针对透视问题,网络需要根据不同位置的人头大小,自适应调整感受野或特征融合权重。尺度注意力通常配合多分支或者空洞卷积金字塔来使用,让每个位置自己决定“用大感受野还是小感受野”。
三种注意力不是互斥的,实际工作中往往两两组合、甚至三管齐下。但组合的时候要注意参数量和计算量,我后面在调参会细讲。
2.2 Attention Scaling vs Attention Masking:关键区别
注意力机制被引入人群计数的早期,大多数方法是走 Masking 路线:生成一张 0 到 1 的 mask,然后和特征图逐元素相乘,把不重要的区域直接压成接近 0。
Attention Scaling 的思路完全不同。它生成的不再是“要不要保留”的开关信号,而是一个连续的缩放系数,作用不是“抹掉”背景特征,而是把前景区域的响应“调大”。我当时看这篇论文时印象很深的一个点是:Scaling 操作保留了特征图里原本的信息,只是对重要区域做增强。
这个区别用生活化的比喻来说:Masking 是关灯,把不需要的区域直接变黑;Scaling 是调亮度,把主角照亮、配角调暗,但画面细节还在。在人群计数这种密集重叠场景里,“关灯”很容易误杀特征——比如一个人头旁边的背景纹理可能是区分两个相邻头部的关键边界信息,如果被 mask 抹掉,密度图就会糊成一团。而 Scaling 只做“增强”不做“消除”,边界信息能留下来,最后预测的密度分布往往更精细。
实践中的具体操作是:设原始特征为 F,注意力图为 A(取值范围通常在 [0, 1] 或 [0, 2]),缩放后的特征 F' = F ⊙ (1 + A) 或 F' = F ⊙ (α + β·A)。这里的 1 保证了即使注意力值为 0,原始特征也不会被完全抑制;α 和 β 控制缩放范围,让增强幅度被限制在合理区间。这个带“保底”的设计是 Scaling 能稳定提升的关键,我复现时试过直接把 F 乘 A,效果反而不如 baseline,原因就是背景区域特征被过度压制。
3. Attention Scaling 方法拆解:核心模块与设计动机
3.1 整体 Pipeline 和各模块位置
整个网络结构可以分成四段:
主干网络(Backbone):通常用去掉分类头的 VGG16 或 ResNet50,负责提取多尺度语义特征。人群计数任务输入分辨率高,主干一般不会太深,VGG16 是经典选择。
注意力生成模块:从主干某一层(或多层)特征出发,经过若干卷积和激活函数,生成空间注意力图。这是整个方法的核心改动点。
缩放融合模块:把注意力图和主干特征逐元素相乘(带上保底系数),输出缩放后的特征。有些实现还会在缩放后接一个 1×1 卷积做特征重标定。
密度图回归头:一般是一组空洞卷积(Dilated Convolution)或者转置卷积组成的解码器,把特征图放大回输入分辨率,输出密度图。
模块位置的选择很关键。我实际比较过三种接法:
- 只接在高层特征(靠近输出层):注意力图语义强,但空间分辨率低,密集小头容易被漏掉。
- 只接在浅层特征:空间细节保留好,但语义信息弱,容易把背景纹理误判成人头。
- 多层同时做缩放:效果最好,但计算量显著增加,需要做速度与精度的权衡。
论文里的默认做法更接近第三种思路——在多个层级都做注意力缩放,低层负责细节保留,高层负责语义引导。工程化简时可以把注意力模块只挂到高层和中间层,低层用轻量通道注意力替代,能在精度损失很小的情况下省下不少推理时间。
3.2 注意力生成分支的细节设计
生成注意力图的具体操作,我按复现时的理解拆成四步:
第一步,从主干特征 F 出发,用几个 3×3 卷积做特征提取和通道压缩,把 512 或 1024 通道压到 128 左右。这样后面的计算量小很多,注意力分支不会喧宾夺主。
第二步,用 1×1 卷积输出单通道特征图,尺寸和输入特征一致。
第三步,激活函数做非线性映射。论文里用 Sigmoid 把输出映射到 [0, 1],然后在缩放时通过 1+A 变成 [1, 2]。我试过直接输出到 [0, 2] 的 Softplus 变体,也试过在 Sigmoid 前加一个可学习的缩放参数,效果差别不大。但初始化的差异影响巨大,这个我在第 5 章会专门讲。
第四步,可选的后处理。有人会对注意力图做一次高斯平滑,降低逐像素噪声。我测试下来平滑对最终 MAE 影响不大,但对密度图的可视化效果帮助明显,如果是要给业务方看图,建议加上。
为什么用 Sigmoid 而不是 Softmax?这是一个值得记住的点。Softmax 是竞争机制,所有位置的权重加起来为 1,放大一个区域必然压缩另一个区域,这不符合人群计数的需求——我们希望对所有潜在人头区域都增强,而不是“二选一”。Sigmoid 是逐元素独立激活,每个位置可以同时很高,不会互相抑制。
3.3 损失函数设计:全局与局部的平衡
人群计数最基础的损失是密度图的逐像素欧氏距离:
L = (1/2N) Σ ||D_pred - D_gt||²
这个损失简单有效,但有个隐含问题:它鼓励每个像素的预测值和真实值尽量一致,却没有显式约束“局部区域的和”要准确。结果就是网络可能在某个区域预测多 0.5、另一个区域少 0.5,像素级误差不大,但局部区域的计数是错的。
Attention Scaling 配套的损失函数通常会加一个局部计数一致性约束。做法是把密度图划分成若干个不重叠的小块(比如 8×8 或 16×16 的 grid),对每个小块分别求和,再计算预测值和真实值的误差:
L_local = (1/M) Σ (sum(D_pred_block) - sum(D_gt_block))²
这个损失和全局 MAE 是互补的:全局损失管总量,局部损失管分布。我复现时发现加了局部损失之后,密度图的峰值位置更准,尤其在人群扎堆的区域,不会出现“人数对了但人头位置全偏了”的情况。
还有一个小 trick:真实密度图的生成用的是基于几何距离自适应的高斯核,头部密集区域核的 σ 小,稀疏区域 σ 大。这个 σ 的设定直接影响训练难度,核太小监督信号过于稀疏,核太大密度图会非常平滑、难以回归出尖锐峰值。需要根据数据集的平均人头间距反复试验,没有万能参数。
3.4 与多尺度模块的配合方式
Attention Scaling 不是孤立模块,它和现有的多尺度方案能很好兼容。我当时复现时试过两种组合:
一种是把注意力缩放挂在空洞卷积金字塔(ASPP)之后。ASPP 用不同扩张率的空洞卷积捕捉多尺度上下文,注意力缩放负责强化每个尺度特征里的人群区域,两者各司其职。
另一种是类似 FPN 的自顶向下融合。高层特征经过注意力缩放后,通过上采样和低层特征相加,相当于把语义注意力“传递”给低层细节。这种做法在小人头场景收益最明显,因为低层特征经过语义注意力引导后,对“细节里哪些属于人头”的判断会准很多。
需要注意的坑是,注意力模块和金字塔模块堆叠后会明显增加显存消耗。我当时在一块常规 24GB 显存的显卡上训练 512×768 输入,网络深度稍大就直接 OOM。解决办法是把注意力模块的中间通道从 128 降到 64,或者对特征图做一次 2 倍下采样再生成注意力,再上采样回原尺寸。后一种方案精度损失很小,推荐优先考虑。
4. 实验效果与关键结论:提升来自哪里
4.1 在公开基准上的表现
我在几个常见的人群计数公开基准上复现了 Attention Scaling,整体结论和论文一致:相比不带动力的 VGG16 baseline,MAE 大约能降 10% 到 15%。这个幅度在拥挤场景数据上更明显,在稀疏场景数据上提升相对小一些,但仍然稳定为正。
一个比较有意思的现象是:MSE 的降幅往往比 MAE 更大。这说明注意力缩放不只是“整体数对了”,更多是让那些极端拥挤的样本不再崩坏。我做业务评估时很看重这个特性,因为极端拥挤样本才是安全预警真正需要守住的场景。
跨场景泛化能力也算一个隐性收益。我在一个数据集上训练,直接拿到另一个风格差异较大的数据集上测试,加了注意力缩放的模型掉点明显更少。原因推测是注意力图学习的是“头部区域和背景区域的特征差异”,这种差异在不同场景下是共通的,相当于给模型加了一层不变性约束。
4.2 注意力图可视化:模型到底在看什么
训练完成后把注意力图单独导出来看,能发现一些规律。正常收敛的模型,注意力图在真实人头位置有明显的高响应,头部中心最亮,边缘有平滑过渡带;背景区域响应趋近于 0,但不是那种硬切式的断崖,而是有一个渐变衰减。
我特别关注过渡带这个现象。它说明 Scaling 机制没有简单地把背景“一棒子打死”,而是在人头边界附近保留了梯度信息。这正好和前面讲的“Scaling 优于 Masking”呼应:边界残差特征被保留下来以后,密度图回归头才能把相邻人头区分开。
还有一个值得注意的现象:在严重遮挡区域,注意力图往往在“可见的半个头”位置响应最强,而完全看不见的头部区域也会有弱响应。这其实是一种合理的“推测性关注”:网络学会了利用上下文判断被遮挡处大概率有人。这种能力很难通过人工设计特征实现,是注意力机制自带的语义建模能力。
4.3 Ablation Study 的启发:空间注意力权重更高
拆解来看,空间注意力的贡献通常大于通道注意力。这个结论符合任务直觉:人群计数本质上是一个定位问题,“在哪里数”比“用什么特征数”更关键。通道注意力的增益虽然小,但叠加之后依然稳定为正,主要作用体现在缩小尺度、颜色变化较大的场景里。
还有一个 ablation 的结果启发很大:把注意力缩放从训练好的模型里移除、直接用回原始特征,精度会立刻掉回接近 baseline 的水平。这说明注意力模块在推理时不只是“帮训练收敛”,而是作为特征重标定的一部分持续发挥作用。这也提醒我们,模型剪枝和蒸馏时不能简单把注意力分支扔掉,需要让它参与蒸馏目标的构建。
5. 复现要点与调参心得:从论文到可用模型
5.1 环境搭建与训练配置
复现这个方法的门槛不高,常规的 PyTorch 环境就行。我推荐以下配置组合:
主干网络用 ImageNet 预训练的 VGG16,去掉最后的分类层,保留到 conv5。回归头用 4 层空洞卷积,扩张率从小到大排列,输出单通道密度图。注意力分支由 2 个 3×3 卷积加 1 个 1×1 卷积组成,中间通道 128。
输入尺寸建议在训练时做多尺度随机裁剪,比如从 512×512 到 768×768 之间随机取。多尺度训练对 dense 场景特别重要,因为人和人的尺度变化在真实场景里跨度极大。数据增强至少要包含随机水平翻转、随机亮度扰动和随机裁剪,我试过加随机对比度和饱和度扰动,也能再提升一点泛化性。
训练轮数要足够多。人群计数的收敛速度比分类任务慢不少,我在单个数据集上通常至少训练 300 轮,batch size 8 到 16,初始学习率 1e-4,用余弦退火调度。和分类任务不同,这个任务的学习率不能设太高,否则密度图的数值会震荡很长时间不收敛。预训练主干网络的前几层可以冻结或使用较小的学习率,避免大梯度破坏底层特征。
5.2 注意力分支的初始化与训练节奏
这是我要重点提醒的部分,也是我踩过最深的一个坑。
注意力分支如果从头随机初始化,训练初期会输出一堆噪声权重。这些噪声经过缩放操作流入回归头,会严重干扰密度图的学习。尤其是 Sigmoid 输出接近 0.5 的随机权重,会让每个位置的响应随机放大 1.5 倍,相当于给训练数据加了巨大的噪声。
解决方法是控制注意力分支的初始化:在训练开始前,把 Sigmoid 之前的卷积偏置设为 -2 或 -3,使初始注意力图输出接近 0。这样缩放操作一开始几乎退化为 F' = F,注意力分支不会干扰主干网络热身。训练几十轮之后,再让注意力分支自然开始调整。
另一个好用的训练节奏是“两阶段”:第一阶段固定主干网络和回归头,只训练注意力分支几百步;第二阶段全部放开一起训练。这样能让注意力分支快速建立“大概往哪里看”的能力,之后再微调主干特征去配合它,比所有模块从零同时学要稳定得多。
5.3 GT 密度图生成细节
GT 密度图的质量直接决定模型上限。生成密度图最常见的方法是几何自适应高斯核:
对每个人头标注点 (x_i, y_i),计算到最近邻人头标注点的距离 d_i,把高斯核标准差设为 σ_i = k * d_i(k 通常取 0.3 到 0.5 之间),然后叠加所有高斯核得到密度图。
这个 k 值对训练影响很大。k 太大,密度图高斯峰相互叠加,看起来是一团糊,模型学不到清晰的头部中心响应;k 太小,每个高斯核几乎是一个点,监督信号稀疏,模型更难收敛。我实际使用时的经验是:先统计训练集里人头间距的分布,把 k 设置为人头平均间距的 0.3 倍左右,效果好于盲选固定值。
还有一个容易忽略的坑:密度图的积分值应该等于总人数,但 GPU 上训练时如果做了随机裁剪,裁剪边缘部分高斯核会被截断,导致裁剪区域内的积分和实际标注不一致。需要对裁剪后的密度图重新计算积分并做整体归一化,或者直接把损失函数设计成尺度无关的相对误差形式。
5.4 推理阶段的优化策略
训练完成后落到推理阶段,有几个细节能明显提升实际效果:
输入图片需要做一次全局归一化。人群计数模型对亮度分布很敏感,直接喂原始图片会导致不同摄像头间的预测差异很大,统一归一化能显著提升跨摄像头泛化。
密度图后处理建议加上一个阈值过滤和一个小核中值滤波。阈值过滤可以把背景区域的微小噪声响应清零,中值滤波可以让密度图的峰值更光滑。这两个操作几乎不增加耗时,但视觉效果和下游热力分析的质量都会好很多。
如果想进一步压缩推理耗时,可以把注意力分支的中间通道从 128 降到 64,并把 3×3 卷积改成深度可分离卷积。这样的修改会让 MAE 有一定上升,但幅度通常可控,适合边缘端部署场景。
FP16 量化时需要注意:注意力图经过 Sigmoid 后的取值范围在 [0, 1],数值很小,FP16 的精度损失可能导致注意力边界模糊。我测试下来,把注意力图保持在 FP32,只对主干特征做 FP16,可以兼顾速度和精度。
6. 常见问题与排查技巧实录
6.1 注意力图全黑或全白怎么办
训练一段时间后把注意力图可视化,发现要么全黑、要么全白,这个现象有几个常见原因:
如果注意力图全黑,最可能的因素是初始化偏置过大或学习率太小,注意力分支一直没能激活。先把 Sigmoid 前的偏置减小一点,再确认注意力分支的学习率没有设为主干的十分之一以下。
如果注意力图全白,说明缩放系数饱和了。检查数据增强里是否有过强的亮度扰动,或者损失函数里是否缺少对注意力值的正则约束。可以加一个稀疏正则项,鼓励注意力图只在局部区域高响应,而不是全图均匀激活。
6.2 密度图整体偏糊,峰值起不来
这个现象通常和 GT 密度图的生成参数有关。高斯核标准差设得太大,监督信号就是一团糊,模型自然学不出锐利峰值。解决的思路是调小 k 值,但要注意不能太小导致训练不收敛,需要做一个梯度检查:从训练集里抽几千个 patch,统计真实密度图的最大值和均值,理想情况应该呈现稀疏而尖锐的分布,而不是密集平滑。
如果 GT 没问题,那就检查损失函数。欧氏损失天然倾向于“平均预测”,如果想获得锐利峰值,需要配合局部计数损失或者使用 Charbonnier 损失这类对异常值更敏感的形式。
6.3 显存溢出与训练速度慢
显存溢出先检查是不是输入尺寸过大。人群计数训练通常要用高分辨率输入,可以先用 384×384 跑通流程,再逐步放大。如果非要用大图,配合梯度累积和混合精度训练,大多数情况下能解决问题。
训练速度慢的瓶颈通常在于 GT 密度图的实时生成。如果每次迭代都在 CPU 上重新计算高斯核,会拖慢整体训练进度。建议把所有 GT 密度图预处理并缓存成 NumPy 文件,训练时直接用随机裁剪读取,能在不损失随机性的前提下节省大量时间。
下表是我整理的常见问题速查,方便逐个排查:
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| 训练 loss 不降 | 学习率过大或 GT 核过小 | 调低学习率,增大高斯核 k |
| 注意力图全黑 | 初始化偏置过大 | 调整 Sigmoid 前偏置,提高注意力分支学习率 |
| 注意力图全白 | 缺正则约束 | 加稀疏正则,检查增强强度 |
| 密度图整体偏糊 | GT 高斯核太大 | 调小 k 值,检查局部损失是否生效 |
| 小目标计数偏低 | 输入分辨率不够 | 提高输入分辨率,加入浅层注意力缩放 |
| 跨摄像头掉点严重 | 未做全局归一化 | 推理前统一归一化,对比度自适应 |
6.4 我在实际训练中的一个小技巧
最后分享一个我实际使用时的技巧:在训练的最后一小段(比如最后 10% 轮次),把 GT 密度图的高斯核标准差整体缩小 20%。这个操作相当于在最后阶段做了一个“锐化微调”,迫使模型把注意力集中在更精确的头部中心位置,而不是满足于一个宽泛的高斯响应。我试过多个数据集,MAE 都能再降一点点,而且不会带来过拟合的副作用。
一个更稳定的做法是在训练中逐渐衰减高斯核的 k 值,而不是在最后突然改变分布。具体做法是每 10 轮把 k 乘以 0.95,让监督信号从“宽泛引导”平滑过渡到“精确聚焦”。这个 trick 看起来简单,但实际效果比我试过的很多复杂模块都要明显,强烈建议尝试。
7. 从论文到工程:Attention Scaling 的落地边界
7.1 在业务系统里的实际表现
在把 Attention Scaling 移植到实际业务系统的经历里,表现最好的场景是地铁站和大型活动现场的实时人流统计。这类场景的共同点是机位固定、视角稳定、人群密度高。模型输出的密度图可以直接拿来生成区域热度图,再叠加一个简单的区域积分逻辑,就能实现“哪个区域超过安全容量”的自动预警。
在俯视 45 度角的机位上,注意力缩放的优势比平视角更明显。因为俯视场景里人头往往重叠得更严重,普通模型容易把多个近距离的人头合并成一个高亮区域,而注意力缩放由于在边缘保留了清晰的过渡带,密度图的峰值分离度明显更好,计数更准。
7.2 和行人检测、目标跟踪方案放在一起比较
人群计数除了密度图回归,还有一个常见技术路线是检测加跟踪(Detection + Tracking)。两条路线各有各的边界:
检测跟踪方案在稀疏场景下精度可以做得非常高,每个人头的框和轨迹都是现成的,可以直接支撑“逆行识别”“区域停留时长”这类高级分析。但在超高密度场景下,检测框重叠严重,跟踪 ID 频繁切换,整套系统很容易崩溃。
密度图方案的优势是天然适合高密集场景,即使一个人头只有几个像素,模型也能输出一个合理的密度响应。缺点是缺少实例级信息,没有办法回答“每个人走到哪里去了”这类问题。
Attention Scaling 解决的正是密度图方案的短板之一——密集场景下的定位精度和峰值分离能力。所以它和检测跟踪不是替代关系,而是在高密度场景里补齐了密度图方案的短板。实际工程里可以做一个简单的策略融合:密度低时跑检测跟踪,密度超过阈值时切换密度图模型。
7.3 数据标注与领域迁移
人群计数的落地瓶颈经常不在模型,而在标注。密度图方案要求对每个人头中心点做标注,一个 1000 人的密集场景图片标注成本极高。实际项目里更常见的做法是用半自动标注:先跑一个预训练模型生成候选点,人工只负责修正漏标和错标,再通过课程学习的方式逐步提升模型能力。
跨场景迁移时,Attention Scaling 的作用主要体现在源域和目标域的特征对齐上。如果在目标域只有少量标注数据,可以固定主干的低层参数,只微调注意力分支和回归头。因为注意力分支的参数空间小,小样本下更容易学到目标域的“人头注意力先验”,迁移效果往往比全量微调更好。
7.4 后续扩展方向
Attention Scaling 这个思路其实还能扩展到不少相关方向。比较直接的是视频计数,把时间维度的注意力加上去,对帧间的密度图做时序平滑,可以降低闪烁和抖动。另一个方向是弱监督计数,不标注具体人头位置,只用区域级人数的弱标签,注意力图可以作为人头的伪标注信号参与训练。
还有个我一直在关注的方向是用注意力缩放做跨模态融合,比如 RGB 图像和红外图像的注意力共享。夜间场景下红外图像的头部轮廓更清晰,RGB 图像有颜色纹理信息,两个模态各自生成注意力图然后融合缩放,理论上能显著提升夜间人群计数精度。这块目前公开工作还不多,但实验空间很大。
写在最后
我从第一次跑通 Attention Scaling 到现在,最大的体会是:这个方法的核心价值不在于引入了一个新模块,而在于重新理解了注意力在计数任务里的角色。Masking 思维根深蒂固,几乎所有引入注意力的工作都默认用乘法去“抑制”背景,Attention Scaling 换了一个角度——只做增强、不做消除,配合保底系数把特征的完整信息保留下来,反而让密集场景下的密度分布预测更准。这种“少即是多”的设计思路在工程里很值得借鉴。
如果你正在做人群计数方向的实验,我的建议是先在一个公开数据集上把 baseline 跑通,然后只加注意力缩放这一个变量,别的都不动,观察注意力图的可视化结果和 MAE/MSE 变化。确认有效以后,再逐步加入局部计数损失、多尺度模块和训练技巧。每次只动一个变量,你就能清楚地知道每个改动到底带来了什么,不会陷入“改了一堆但不知道为什么变好”的困境。人群计数这个方向看起来简单,实际坑非常多,希望这篇复盘能帮你少走一些弯路。