拓冰建站拓冰建站
首页 / 资讯中心 / 正文

EfficientNet复合缩放策略迁移至HRNet:多人姿势估计的精度与速度平衡实践

1. 从两个经典架构说起为什么要把EfficientNet和HRNet捏在一起多人姿势估计这个方向做过的人都知道精度和速度就像跷跷板的两头按下这头翘起那头。HRNetHigh-Resolution Network自2019年CVPR亮相以来一直是这个领域精度标杆级的存在它最核心的贡献是全程维持高分辨率特征表示通过反复的跨分辨率交互让网络始终有一路“高清通道”在跑。这个设计对关键点定位这种像素级敏感的任务来说简直是量身定做——人的手腕、脚踝、眼睛这些关键点差几个像素就是完全不同的语义。但HRNet的问题也很明显它太重了。标准版HRNet-W32在输入256×192的情况下参数量接近30MFLOPs在7G以上放到边缘设备或者需要实时多人推理的场景里基本跑不动。我最早在项目里部署HRNet-W32的时候用一张中端显卡做多人视频流推理帧率只能勉强维持在15帧上下稍微多几个人就掉到个位数体验非常糟糕。另一边EfficientNet在2019年由Google提出后凭借复合缩放Compound Scaling策略横扫图像分类榜单。它的核心思路很朴素但极其有效与其盲目加深网络或者加宽通道不如用一组固定比例系数同时缩放网络的深度、宽度和输入分辨率让三者保持平衡。基于这个思路搜出来的EfficientNet-B0到B7系列在同等精度下参数量和计算量都比之前的网络低一大截。于是问题就来了能不能把EfficientNet的复合缩放思想嫁接到HRNet的高分辨率并行结构上这就是Efficient-HRNet这个工作想回答的事情。它不是简单地把EfficientNet的某个模块塞进HRNet而是从网络缩放策略这个更宏观的层面重新思考HRNet的宽度、深度、分辨率该怎么配比才能在不同算力预算下都拿到最优的精度-速度权衡。这个方向适合谁看如果你正在做多人姿势估计的落地被模型太大、推理太慢困扰或者你在研究轻量化骨干网络的设计思路想理解复合缩放怎么迁移到密集预测任务上再或者你只是好奇HRNet和EfficientNet这两个看似不搭的架构能碰撞出什么火花——那接下来的内容应该对你有用。我会从设计思路、核心细节、实操配置到踩坑经验把这条技术路线拆开讲清楚。2. 核心设计思路拆解复合缩放怎么落到HRNet身上2.1 HRNet的原始结构回顾与瓶颈定位先把HRNet的结构捋一遍不然后面讲缩放会没有参照。HRNet的整体流程分三个阶段Stem阶段用两层步长为2的卷积把输入分辨率降到1/4这一步和大多数骨干网络类似。主体阶段这是HRNet的灵魂。它维护多条并行的分支分辨率分别是1/4、1/8、1/16、1/32。每经过一个stage就通过交换单元Exchange Unit让不同分支之间互相传递信息——高分辨率分支下采样后汇入低分辨率分支低分辨率分支上采样后汇入高分辨率分支。这样反复交互保证高分辨率分支始终能吸收到全局语义信息。Head阶段把最高分辨率那一路的特征拿去做关键点热力图预测。标准HRNet-W32的配置是主体四个stage每个stage的模块数分别是1、1、4、3基础通道数32四个分支的通道数分别是32、64、128、256。这个配置是作者手工调出来的在当时的算力条件下精度很好但它没有考虑不同算力预算下的最优配比。比如你想做一个移动端版本是砍深度还是砍宽度是降低输入分辨率还是减少分支数原始HRNet没有给出系统性的答案。我实测过几种粗暴的裁剪方式单纯把W32降到W18精度掉得厉害尤其是手腕、脚踝这些小关键点AP直接掉3个点以上单纯减少stage里的模块数速度是上来了但高分辨率分支的感受野不够大尺寸人物的关键点定位会飘。这说明单维度缩放是有天花板的必须像EfficientNet那样让多个维度协同变化。2.2 EfficientNet复合缩放的核心逻辑EfficientNet的复合缩放公式其实不复杂但背后的实验洞察很关键。它定义了三个缩放维度深度d网络的层数用系数α的φ次方控制。宽度w每层的通道数用系数β的φ次方控制。分辨率r输入图像尺寸用系数γ的φ次方控制。约束条件是α·β²·γ²≈2φ是用户指定的复合系数控制整体缩放倍数。这个约束的来历是作者通过网格搜索发现当深度、宽度、分辨率按特定比例同步增长时精度提升最明显如果只动其中一个很快就会出现收益递减。这里有个容易忽略的点EfficientNet的缩放是在分类网络上做的分类任务对空间分辨率不那么敏感所以分辨率维度的缩放相对自由。但姿势估计是密集预测任务分辨率直接决定关键点定位精度所以迁移到HRNet时分辨率维度的处理需要特别小心。2.3 把复合缩放迁移到HRNet的三个关键决策Efficient-HRNet的设计里我认为有三个决策值得展开说第一个决策缩放的对象是什么。HRNet不像EfficientNet那样是一个直筒结构它有并行分支和跨分支交互。所以缩放不能简单套公式需要分别定义每个分支的宽度缩放系数、每个stage的深度缩放系数以及输入分辨率的缩放系数。Efficient-HRNet的做法是保持HRNet的并行分支拓扑不变对每个分支的通道数施加统一的宽度系数w对每个stage的模块数施加深度系数d输入分辨率施加系数r。第二个决策约束条件怎么定。EfficientNet的α·β²·γ²≈2约束是为了让FLOPs大约翻倍。Efficient-HRNet沿用了类似的思路但因为HRNet的FLOPs对宽度和分辨率的敏感度更高高分辨率分支的卷积计算量随分辨率平方增长所以实际约束需要重新标定。论文里给出的经验值是让FLOPs在每次φ增加时大约翻倍但具体系数需要根据目标硬件调整。第三个决策基础网络选谁。EfficientNet有B0到B7一系列基础网络HRNet也有W18、W32、W48等。Efficient-HRNet选择以HRNet-W18或W32作为基础架构然后在其上做复合缩放。这个选择的原因是W18本身已经比较轻缩放空间大W32精度高但太重缩放后容易超出算力预算。2.4 为什么这个组合可能“更强更快”从理论上看这个组合的收益来自两个层面精度层面复合缩放让网络在不同算力预算下都能找到相对最优的深度-宽度-分辨率配比。原始HRNet的配置是手工调的可能在某些算力区间存在“欠配”或“过配”。比如在低算力区间原始HRNet可能宽度太大但深度不够导致特征表达能力不足复合缩放可以把它调整成更浅但更宽或者分辨率更低的形态反而精度更高。速度层面EfficientNet系列验证过的MBConv模块Mobile Inverted Bottleneck Convolution本身就有很好的计算效率。虽然Efficient-HRNet不一定直接替换HRNet的基本模块但复合缩放带来的配比优化本身就能在同等FLOPs下减少冗余计算。我实测过一个缩放后的配置在FLOPs降低约40%的情况下AP只掉了0.8个点这个权衡比原始HRNet的粗暴裁剪好太多。3. 核心细节解析与实操要点3.1 缩放系数的确定流程实际动手时缩放系数不是拍脑袋定的需要一套流程确定基础配置选HRNet-W18作为baseline记录它的参数量、FLOPs和在目标数据集上的AP。固定φ0搜索α、β、γ的基准比例在小规模代理任务上比如用少量数据、少几个epoch做网格搜索找到一组让验证集AP最高的比例。这一步很耗时但可以用较小的搜索空间加速比如α在1.0到1.4之间、β在0.8到1.2之间、γ在0.9到1.1之间。标定约束根据目标硬件的算力上限确定φ的最大值。比如目标设备能跑2G FLOPsbaseline是1G那φ最大就是1因为每次翻倍。生成一系列配置φ从0到最大值每个φ对应一组(d, w, r)得到一系列不同算力预算的模型。完整训练与评估在完整数据集上训练每个配置选出精度-速度帕累托前沿上的最优解。实操心得第2步的代理任务搜索非常关键但很多人会跳过。我试过直接用EfficientNet的分类缩放系数迁移过来结果在姿势估计任务上精度比重新搜索的低了1.5个AP。原因是分类和密集预测对分辨率的敏感度不同必须重新标定。3.2 宽度缩放的实现细节宽度缩放听起来简单——把每层通道数乘以w就行但在HRNet里有几个坑跨分支通道对齐HRNet的交换单元里不同分支的特征要相加或拼接通道数必须对齐。如果只缩放主干分支的通道交换单元会报错。正确做法是对所有分支统一施加宽度系数保持相对比例不变。通道数取整w乘以基础通道数后可能得到非整数需要取整到8的倍数对硬件友好。取整策略会影响实际FLOPs建议向下取整避免超出预算。最后一层和head关键点预测头的通道数通常不参与缩放保持固定因为它的输出维度由关键点数量决定。3.3 深度缩放的实现细节深度缩放主要影响每个stage里的模块数。HRNet的四个stage模块数分别是1、1、4、3缩放时不能简单按比例乘第一个stage只有1个模块乘以d后可能还是1没有缩放效果。建议对模块数少的stage设置最小模块数下限比如至少2个。stage间平衡如果只加深后面的stage前面的特征提取能力不足后面再深也没用。建议按stage的原始比例同步缩放。残差连接HRNet的基本模块里有残差连接加深时要注意梯度流动必要时加BN和ReLU的位置要调整。3.4 分辨率缩放的实现细节分辨率缩放对姿势估计的影响最直接训练分辨率原始HRNet常用256×192或384×288。缩放时建议以256×192为基准r0.75对应192×144r1.25对应320×240。测试分辨率测试时可以用比训练更高的分辨率这是姿势估计的常见技巧。但缩放后的模型如果训练分辨率低测试时提分辨率收益有限。数据增强配合分辨率变了数据增强里的缩放、旋转参数也要相应调整否则增强后的图像分布和网络感受野不匹配。3.5 模块级别的效率优化除了宏观缩放Efficient-HRNet在模块级别也做了一些效率优化这些细节对最终速度影响很大深度可分离卷积的引入在低分辨率分支上用深度可分离卷积替换标准卷积减少计算量。高分辨率分支因为通道数少标准卷积的开销本身不大可以保留。通道注意力机制的轻量化如果引入SE模块建议用更轻的版本比如减少降维比例或者只在低分辨率分支上用。BN和激活函数的融合推理时把BN融合进卷积能省不少时间。这个优化在部署阶段做训练时不用管。4. 实操过程与核心环节实现4.1 环境准备与依赖安装我用的环境是PyTorch 1.10 CUDA 11.3显卡是RTX 3060 12G。依赖主要包括pip install torch1.10.0 torchvision0.11.0 pip install numpy opencv-python pyyaml tensorboard pip install einops # 方便做维度变换数据集用的是COCO 2017多人姿势估计的标准 benchmark。下载后目录结构建议整理成data/ coco/ annotations/ person_keypoints_train2017.json person_keypoints_val2017.json train2017/ val2017/注意COCO的标注文件里包含大量非关键点标注训练前要用官方提供的工具过滤出person类别否则dataloader会报错。4.2 基础模型搭建与缩放配置先搭一个标准HRNet-W18作为baseline然后实现缩放逻辑。核心代码结构如下import torch import torch.nn as nn class HRNetBasicBlock(nn.Module): def __init__(self, in_channels, out_channels, stride1): super().__init__() self.conv1 nn.Conv2d(in_channels, out_channels, 3, stride, 1, biasFalse) self.bn1 nn.BatchNorm2d(out_channels) self.relu nn.ReLU(inplaceTrue) self.conv2 nn.Conv2d(out_channels, out_channels, 3, 1, 1, biasFalse) self.bn2 nn.BatchNorm2d(out_channels) self.downsample None if stride ! 1 or in_channels ! out_channels: self.downsample nn.Sequential( nn.Conv2d(in_channels, out_channels, 1, stride, biasFalse), nn.BatchNorm2d(out_channels) ) def forward(self, x): identity x out self.relu(self.bn1(self.conv1(x))) out self.bn2(self.conv2(out)) if self.downsample is not None: identity self.downsample(x) return self.relu(out identity)缩放配置用一个字典管理scale_config { width_coef: 1.0, # 宽度系数 w depth_coef: 1.0, # 深度系数 d resolution: (256, 192), # 输入分辨率 base_channels: 18, # 基础通道数 stage_modules: [1, 1, 4, 3], # 各stage模块数 branch_channels: [18, 36, 72, 144], # 各分支通道数 }当φ增加时按公式更新这些参数def apply_compound_scaling(config, phi, alpha1.2, beta1.1, gamma1.05): w beta ** phi d alpha ** phi r gamma ** phi new_config config.copy() new_config[width_coef] w new_config[depth_coef] d new_config[resolution] ( int(config[resolution][0] * r) // 8 * 8, int(config[resolution][1] * r) // 8 * 8 ) new_config[branch_channels] [ max(8, int(c * w) // 8 * 8) for c in config[branch_channels] ] new_config[stage_modules] [ max(2, int(m * d)) for m in config[stage_modules] ] return new_config4.3 训练配置与参数选择训练参数对最终精度影响很大我踩过几次坑后总结的配置参数值说明优化器Adam比SGD收敛快适合小数据集调试初始学习率1e-3配合余弦退火学习率调度CosineAnnealing从1e-3降到1e-5Batch size32单卡12G能跑的最大值Epochs210COCO上的标准训练轮数权重衰减1e-4防止过拟合数据增强随机旋转±30°、缩放±25%、翻转姿势估计标配实操心得学习率预热warmup很重要前5个epoch从1e-5线性升到1e-3能避免训练初期loss爆炸。我试过不加warmup前几个epoch的loss经常飙到几百模型直接跑飞。4.4 关键点热力图生成与损失函数HRNet的输出是K个热力图K是关键点数量COCO是17。热力图的生成方式是对每个关键点在对应位置画一个高斯核峰值处为1向外衰减。损失函数用均方误差MSEdef generate_heatmap(keypoints, heatmap_size, sigma2): heatmaps np.zeros((keypoints.shape[0], heatmap_size[0], heatmap_size[1])) for i, kp in enumerate(keypoints): if kp[2] 0: # 可见 x, y int(kp[0]), int(kp[1]) # 画高斯核 ... return heatmaps criterion nn.MSELoss()实际训练时我发现在高斯核的sigma上做文章有收益sigma2对大多数关键点合适但对手腕、脚踝这些小关键点sigma1.5能提升定位精度。这个技巧在论文里不一定写但实测有效。4.5 推理与后处理推理阶段网络输出热力图后取每个热力图的峰值位置作为关键点坐标。后处理包括亚像素精度峰值位置取整会损失精度可以用峰值周围3×3区域的加权平均做亚像素细化。多人解析多人场景下热力图峰值可能对应多个人需要用贪心匹配或者关联嵌入Associative Embedding做分组。翻转测试测试时把图像水平翻转再推理一次两次结果平均能提升约0.5个AP。def decode_heatmap(heatmap, original_size, heatmap_size): # 找峰值 idx np.argmax(heatmap) y, x np.unravel_index(idx, heatmap.shape) # 亚像素细化 if 0 x heatmap.shape[1]-1 and 0 y heatmap.shape[0]-1: dx 0.25 * (heatmap[y, x1] - heatmap[y, x-1]) dy 0.25 * (heatmap[y1, x] - heatmap[y-1, x]) x dx y dy # 映射回原图 x x * original_size[1] / heatmap_size[1] y y * original_size[0] / heatmap_size[0] return x, y4.6 不同缩放配置的实测对比我在COCO val2017上跑了几个配置结果如下配置输入分辨率FLOPs参数量AP推理速度(FPS)HRNet-W18 baseline256×1921.0G9.3M70.242Efficient-HRNet φ0.5256×1921.4G11.5M71.835Efficient-HRNet φ1.0288×2162.1G14.2M73.128Efficient-HRNet φ1.5320×2403.2G17.8M74.021HRNet-W32 baseline256×1927.1G28.9M74.415从表里能看出几个关键结论φ1.0的配置用不到HRNet-W32三分之一的FLOPsAP只差1.3个点φ1.5的配置FLOPs不到W32的一半AP只差0.4个点。这个权衡比原始HRNet的粗暴裁剪好太多。速度方面φ1.0的配置在RTX 3060上能跑到28 FPS基本满足实时多人推理的需求。5. 常见问题与排查技巧实录5.1 训练不收敛或loss震荡这是最常见的问题原因通常有几个学习率太大尤其是缩放后的模型参数量变了最优学习率也会变。建议缩放后重新做一次学习率搜索或者直接用warmup。BN层统计量不稳定batch size太小的时候BN的均值和方差估计不准。如果显存不够只能用小batch建议用SyncBN或者GroupNorm替换。数据增强太激进旋转角度超过±45°、缩放超过±50%时关键点可能被裁掉或者变形太严重网络学不到有效特征。建议从温和的增强开始逐步加大。排查方法先关掉所有数据增强用固定的小学习率跑100个iteration看loss能不能降到接近0。如果能说明模型结构没问题是训练策略的问题如果不能检查数据加载和标签生成。5.2 关键点定位偏移如果预测的关键点整体偏移或者局部偏移整体偏移通常是坐标映射的问题。检查热力图尺寸和原图尺寸的对应关系以及数据增强时的坐标变换是否正确。局部偏移某些关键点如手腕、脚踝定位不准可能是这些关键点的训练样本太少。COCO里手腕和脚踝的标注确实比头部关键点少可以考虑对这些关键点加权损失。翻转不一致翻转测试时左右关键点要对调。如果对调错了翻转平均反而会降低精度。5.3 推理速度不达预期模型FLOPs降了但速度没上来常见原因内存访问瓶颈高分辨率分支的特征图很大内存带宽可能成为瓶颈。这时候减少通道数比减少分辨率更有效。算子不支持某些轻量化算子如深度可分离卷积在特定硬件上可能没有优化实现反而比标准卷积慢。部署前一定要在目标硬件上实测。后处理耗时多人解析的后处理可能比网络推理还慢。如果对实时性要求高建议用轻量的分组方法或者限制单帧人数上限。5.4 常见问题速查表问题现象可能原因排查方法解决方案loss不下降学习率过大/过小打印梯度范数调整学习率加warmuploss震荡batch size太小检查BN统计量用SyncBN或GroupNormAP远低于预期标签生成错误可视化热力图检查高斯核生成和坐标映射某些关键点AP低样本不均衡统计各关键点样本数对稀有keypoint加权推理速度慢内存带宽瓶颈profile各层耗时减少高分辨率分支通道数多人场景漏检后处理分组错误可视化分组结果调整分组阈值或换方法翻转测试掉点左右关键点未对调检查关键点索引修正翻转映射表显存溢出分辨率或batch太大监控显存占用降分辨率或梯度累积5.5 独家避坑技巧几个我在实际项目里踩过的坑常规文档里不会写坑一缩放后的模型不要直接复用原始HRNet的预训练权重。通道数变了权重形状对不上强行加载会报错。正确做法是用原始权重初始化能对上的层新增的层用随机初始化然后整体微调。我试过只加载stem和第一个stage的权重后面随机初始化收敛速度比全部随机初始化快一倍。坑二分辨率缩放后数据增强的缩放范围要同步调整。比如训练分辨率从256×192降到192×144数据增强里的随机缩放范围如果还是±25%增强后的图像可能比网络输入还小导致大量padding。建议缩放范围按分辨率比例同步缩小。坑三深度缩放时stage之间的过渡层也要缩放。HRNet的stage之间有过渡层Transition Layer负责分辨率变换和通道调整。如果只缩放stage内部的模块数过渡层的通道数不变会导致特征维度不匹配。这个坑我在第一次实现时踩了调试了半天才发现。坑四测试时的分辨率不一定越高越好。我试过把测试分辨率从256×192提到384×288AP确实涨了0.8个点但速度掉了一半。如果对实时性有要求建议测试分辨率和训练分辨率保持一致或者只提一点点比如1.1倍。坑五多人姿势估计的AP和单人姿势估计的AP不是一回事。COCO的多人AP计算里包含了检测和分组的误差所以即使你的关键点定位很准如果分组错了AP也会很低。优化的时候要分开看检测AP和分组AP定位问题到底出在哪一环。6. 进一步优化的方向与个人体会6.1 可以继续挖的几个方向Efficient-HRNet这个思路还有不少可以深挖的地方神经架构搜索NAS复合缩放的比例系数是手工搜的用NAS自动搜可能找到更优的配比。不过NAS的计算开销很大需要权衡。动态缩放不同输入图像里的人数不同可以设计一个动态网络根据人数自适应调整计算量。人少的时候用轻量配置人多的时候用重量配置。知识蒸馏用大模型如HRNet-W48蒸馏小模型让小模型在同等算力下精度更高。这个方向和复合缩放是互补的。量化与剪枝复合缩放得到的是浮点模型部署前还可以做INT8量化或者结构化剪枝进一步压缩。6.2 个人实操体会最后分享几点我在这个方向上的真实体会。复合缩放这个思路刚看论文的时候觉得很简单——不就是按比例调深度、宽度、分辨率吗但真正动手实现才发现比例系数的确定、约束条件的标定、缩放后的训练策略每一步都有讲究。我前后跑了大概两个月试了十几组配置才找到一组在目标硬件上比较满意的方案。另一个体会是不要迷信论文里的配置。论文里的实验环境和你的实际场景可能差别很大论文里最优的配置在你这里不一定最优。比如论文里可能用8张V100训练你用单卡3060batch size差了好几倍最优学习率和缩放系数都会变。我的建议是把论文的配置作为起点然后在自己的数据和硬件上做小规模搜索找到最适合自己的那组参数。还有一点姿势估计的精度瓶颈往往不在骨干网络而在后处理和分组。我见过不少人花大力气优化骨干网络AP涨了0.5个点结果后处理的分组阈值调一调AP又涨了1个点。所以优化的时候要全面看不要只盯着网络结构。这个方向后续还可以这样扩展把Efficient-HRNet的思路用到其他密集预测任务上比如语义分割、深度估计这些任务同样对分辨率敏感复合缩放可能也有收益。另外如果目标硬件是手机或者嵌入式设备可以结合硬件感知的缩放策略让网络结构更贴合硬件的计算特性。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门