HRNet V1:全程保持高分辨率的多分支骨干网络
1. 论文想解决什么问题HRNet V1 这篇论文我第一次读的时候是有点反直觉的大家都在做“高分辨率特征不好好珍惜先降分辨率再升回来”的套路它偏偏说不要降全程把高分辨率特征保留住。读完以后我最大的感受是这个设计不是因为作者更聪明而是因为它抓住了关键点检测这类任务的本质空间位置精度比什么都重要。HRNet V1 这个名字里的 V1是为了和后面的 V2、V2p 区分开。它重点解决的是一个很具体的问题在做人体关键点检测、语义分割这类需要像素级输出的任务时怎么同时拿到高分辨率的空间细节和足够强的语义信息。传统做法是先下采样到低分辨率提取抽象语义再上采样回高分辨率本质上是一种“先压后解压”的思路。HRNet V1 换成了一种更直接的做法从输入到输出始终保持至少一个高分辨率分支同时用多个并行的低分辨率分支去增强语义再用重复的融合机制让信息和它之间互相交换。这篇论文适合谁读我觉得有三类人值得看。第一类是刚入门姿态估计、想搞明白为什么现在很多开源模型还在用 HRNet 结构的人第二类是做语义分割或者图像分类、想试试“高分辨率表示”是不是能带来提升的人第三类是纯粹想学一下“怎么设计一个和主流套路不一样的网络”的人。它没有特别复杂的数学公式核心思想用几张结构图和几个交换模块就能讲清楚属于那种看起来很高级、实际上很好上手的论文。1.1 从姿态估计的任务特性说起人体关键点检测这类任务输出的是一堆热图每个热图的峰值位置对应一个关节。这个任务对空间分辨率特别敏感如果模型把特征图一路降到原图的 1/32那么一个小关节的定位误差在缩小的特征图上会被放大很多倍。你最后的输出层就算上采样做得再漂亮丢失的细节也很难完全找回来。我在实际做姿态估计的时候对这一点特别有体会。传统方案里编码器部分为了提语义不断下采样特征图越来越抽象但位置信息越来越粗糙。解码器部分又想把分辨率捞回来但上采样只是插值它并不能凭空生成被池化丢掉的信息。HRNet V1 的做法不一样它不放弃高分辨率分支而是让高分辨率分支和低分辨率分支并行跑各自负责不同层面的信息。这样到最后输出特征图天然保留了比较高的分辨率定位精度自然就更稳。1.2 主流方案的共同毛病在 HRNet V1 出来之前主流网络基本是两条路线。一类是沙漏模型那种编码-解码结构先下采样再上采样中间通过跳跃连接保留一些细节另一类是类似带反卷积的骨干网络先把输入缩到低分辨率再接一串反卷积把特征图放大。这两种做法有一个共同点高分辨率特征只在最后阶段才出现前面的网络主体都活在低分辨率世界里。这个设计有个很尴尬的问题低分辨率特征图虽然语义强但空间位置已经变得很钝。你做分类的时候无所谓但做检测和分割时边界、轮廓、关键点位置都是要像素级精度的。HRNet V1 的作者团队等于把问题反过来想了既然高分辨率信息这么重要那就别把它丢掉其他分支负责补充语义大家并行工作。这个想法朴素但确实需要很大的决心因为它改变了整个骨干网络的结构设计方式。2. HRNet V1 的核心设计拆解HRNet V1 的核心可以拆成三个词并行、多分辨率、反复融合。这三个词组合在一起形成了一个和传统梯队结构完全不同的网络骨架。2.1 并行分支而不是上采样理解 HRNet V1最好先忘掉“编码器-解码器”这个思路。它的结构不是一条从上到下的流水线而是多条分辨率不同的支路同时存在。第一支路始终保持比较高的分辨率比如原图的 1/4第二支路是 1/8第三支路是 1/16第四支路是 1/32。高分辨率支路负责保留空间细节低分辨率支路负责提炼语义谁也不用迁就谁。我在读论文的时候第一反应是这个结构会不会很慢并行分支意味着每一层都要同时计算多个尺度的特征计算量确实比单纯一条低分辨率主干要高。但换来的是输出特征的质量最后阶段可以直接从高分辨率分支拿结果不需要一个单独的解码器。论文里的大量实验也表明这个额外计算量在很多任务上能换来实打实的精度提升。2.2 交换单元让多尺度信息真正流通并行分支如果各干各的那基本就是个多尺度网络没有太多新意。HRNet V1 的关键在于每个阶段都引入了交换单元让不同分辨率分支之间互相交换信息。具体来说高分辨率分支会把特征下采样给低分辨率分支低分辨率分支也会把特征上采样给高分辨率分支每个分支在融合后重新调整自己的特征表达。这个交换过程很像一个团队里定期开信息同步会做细节的人把自己看到的情况分享给做宏观的人做宏观的人把整体判断反馈给做细节的人每个人的结论都比自己单独干活时更完整。如果只是最后拼一下很多中间信息是浪费的。HRNet V1 把交换动作放在每个阶段里反复执行所以每一层的特征都带着多尺度的味道。交换单元的细节也不复杂。下采样通常用步长为 2 的卷积上采样通常用双线性插值加 1x1 卷积。不同分辨率之间的连接方式虽然有不同的实现版本但核心逻辑都一样让每个分支输出一个包含自己信息和别人信息的特征图。读论文的时候不需要纠结具体是几个卷积先抓住“交换”这两个字就够了。2.3 Stage 堆叠与网络骨架HRNet V1 整个网络可以分成 Stem 和四个 Stage。Stem 先把输入图像做几次快速降采样把分辨率降到原图的 1/4然后进入第一个 Stage。第一个 Stage 只有一个分支保持 1/4 分辨率从第二个 Stage 开始每次扩展出一个新的低分辨率分支直到第四 Stage 形成四个并行分支。每个 Stage 内部除了常规的残差单元还会有交换单元。残差单元负责在当前分辨率下做特征变换交换单元负责跨分辨率融合信息。这两个东西交替配合构成了 HRNet V1 的骨架。读到这里我发现它其实没有发明特别全新的卷积形式用的还是残差结构真正的创新在于网络组织方式。这对我来说是一个很重要的启发设计网络不一定非要发明新算子把已有模块用更高的组织方式串起来也能带来很大的提升。3. 实现细节与关键参数论文阅读笔记如果只讲思想那跟读科普差不多了。真正要复现或者要在自己项目里用 HRNet V1还是得把配置和数据流说清楚。3.1 典型结构配置我记得比较常见的一个配置是这样的输入图像经过 Stem 之后变成 1/4 分辨率的特征图作为第一分支进入后续网络。第一分支通道数用 C第二分支通道数用 2C第三分支用 4C第四分支用 8C。常见的 C 是 32 或者 48对应开源实现里经常看到的 HRNet-W32、HRNet-W48 这类名字。分支数和分辨率对照起来就是这个感觉阶段分支数各分支相对原图分辨率典型通道数Stage 111/4CStage 221/4, 1/8C, 2CStage 331/4, 1/8, 1/16C, 2C, 4CStage 441/4, 1/8, 1/16, 1/32C, 2C, 4C, 8C我实际看代码时会特别提醒自己这个表里的“通道数”是每分支起始通道数每一层内部还会有残差块的中间通道扩展不要搞混。真正需要理解的是设计规律分辨率越高通道数越少分辨率越低通道数越多。这样算下来各分支的计算量并不会出现某个分支特别夸张的情况。3.2 几个容易被忽略的细节第一个细节是 Stage 内部的重复次数。论文里每个 Stage 通常会堆叠若干个残差单元和交换单元具体数量不是关键关键的是每个阶段做完之后都完成了多轮信息交换。这意味着网络越深不同分辨率之间的特征融合越充分。第二个细节是上采样和下采样的实现方式。交换单元里从高分辨率到低分辨率通常会用一个步长为 2 的卷积如果分辨率差得比较多就连续做几次下采样。从低分辨率到高分辨率一般先做双线性插值再补一个 1x1 卷积来对齐通道数。这些细节在复现时比较容易出问题尤其是通道对齐尺寸对不上会报错通道数不匹配会让融合结果变成噪声。第三个细节是批量归一化的使用。并行分支里每个分支都有自己的 BatchNorm 统计量训练的时候没问题但转成推理模型时如果分支之间的统计量没有固定好有可能出现结果抖动。严格来说这不算 HRNet 特有的问题但在复现时确实值得留意。3.3 损失函数和训练配置姿态估计这一块HRNet V1 输出的仍然是热图损失函数用的是预测热图和目标热图之间的均方误差。目标热图一般会在每个真实关键点位置生成一个高斯响应而不是一个硬编码的 0/1 点。这个细节对训练影响很大高斯核的半径、响应值的大小都会影响最终定位精度。训练方面的常用配置大致是输入分辨率 256x192 或者 384x288数据增强包括随机旋转、随机缩放和随机水平翻转。我在自己跑实验的时候发现数据增强的尺度范围和翻转策略对最终 AP 值的影响甚至比网络宽度还敏感。这也提醒我读论文不能只看结构图训练配置同样属于“论文的干货”。另外HRNet V1 在很多开源实现里还会用上预训练分类权重。先在图像分类这种粗粒度任务上做预训练再把骨干网络迁移到姿态估计或者分割任务上收敛会快很多。严格说这已经有点偏离论文本身但实际项目里很重要。4. 实验结果和个人读后复盘读论文最有意思的部分不是看它刷了多少分而是看它为什么能刷分以及换个任务还能不能继续刷分。4.1 姿态估计为什么更准HRNet V1 的姿态估计结果在常见公开数据集上有明显的提升。我复盘之后觉得提升主要来自三个地方。第一高分辨率分支一直存在所以关节点的空间定位误差天然更小。第二多分辨率融合让语义信息也能渗透到高分辨率分支里模型对遮挡、小目标这类困难情况更有鲁棒性。第三输出热图的峰值更集中不需要依赖很复杂的后处理就能得到不错的结果。有一段时间我还怀疑是不是因为参数量变大了所以结果才变好。后来仔细对比过同参数量级的其他网络发现在相同计算量范围内HRNet 的定位精度仍然占优。这说明问题不仅仅出在容量而是出在“特征的空间信息被保留了多少”这件事上。4.2 迁移到分类和分割任务HRNet V1 原文里不仅有姿态估计还顺手做了语义分割和图像分类实验。分类任务上它没有像传统分类网络那样把分辨率降到 1/32 再全局池化而是保留高分辨率分支再池化精度也能达到主流水平。分割任务上高分辨率细节对边缘和细小物体的帮助更明显比很多带解码器的网络做得更干净。我当时读完感觉HRNet V1 更像一个通用的骨干网络而不是一个只能做姿态估计的专用模型。后面出现的 V2 和 V2p 也是在 V1 基础上改头换尾比如换一个分类头、加一个金字塔池化模块去覆盖更多任务。所以读 V1 的时候如果能把它当成“高分辨率表示学习”的基础框架来理解后面再读 V2 会轻松很多。4.3 复现时踩过的坑第一个坑是“多个分支的初始化不一致”。并行分支如果不做统一的权重初始化训练前期很容易出现某个分支主导、其他分支退化的现象。我后来一般会刻意检查每个分支输出的标准差保证初始化尺度合理。第二个坑是“交换单元里的卷积不加 padding”。HRNet 内部大量使用 3x3 卷积如果 stride 和 padding 没配对分辨率变化之后尺寸对不上。很多报错看起来像维度不匹配实际原因是这里少了一个 padding 配置。第三个坑是“BN 在 batch size 很小的时候非常不稳”。并行分支本身就比普通网络更容易受到 BN 统计量波动的影响我试过在小 batch 下训练损失曲线一直上下跳后来换成了更大的 batch 或者改用同步 BN问题才缓解。这些小问题论文里通常不会写但复现的人十有八九会碰到。4.4 我的思考V1 的边界在哪里虽然 HRNet V1 的设计在当时很有启发性但它不是万能的。第一个明显的短板是计算量偏高因为要同时维护多个分辨率分支对显存很不友好。我在自己机器上跑的时候输入分辨率稍微调大一点显存占用就涨得很快。第二个短板是在纯分类任务上它的优势没有姿态估计那么明显毕竟分类任务对空间分辨率的要求没有那么极端。我现在的看法是HRNet V1 这类结构特别适合“输出要求像素级精准”的任务姿态估计、关键点检测、密集匹配这些场景是它的主场。如果是追求极致推理速度的移动端任务可能需要再做蒸馏或者结构裁剪。读这篇论文给我最大的收获不只是一套网络结构而是一种设计思路先搞清楚任务最需要保护的信息是什么再反过来安排网络结构而不是随手拿一个分类网络当骨干就开跑。最后分享一个小经验。读这类论文时我会把结构图里的每个方块都拆成“分辨率、通道数、模块类型”三个维度来重新画画再把每个阶段的前后尺寸变化写成注释。这个过程虽然慢但做完之后你会发现整个网络就像一张地图一样清清楚楚后面看代码、改结构、迁移任务都会顺手很多。