ViTPose:用于人体姿态估计的简单视觉Transformer基线.
Vison Transformer在视觉识别任务中效果优秀,但还没有工作在姿态估计任务上验证这种结构的有效性。本文提出了用于姿态估计的Transformer网络ViTPose,使用ViT结构作为Backbone,结合一个轻量级的Decoder,在MS COCO关键点估计bechmark上达到SOTA。
1. ViTPose的结构
ViTPose的网络结构设计比较简单,整体采用ViT backbone + decoder的形式。
ViT Backbone分为patch embedding和多个transformer模块。patch embedding将图像分为$d\times d$的patch块。而每个transformer层包含 multi-head self-attention(MHSA) 与 feed-forward network (FFN) 模块。多个transformer层堆叠,构成了backbone。
backbone根据计算量大小可以分别选用Vit-B, ViT-L,ViT-H以及ViTAE-G。
在decoder的选取上,作者选择了两种结构进行了对比:
- 经典Decoder结构,两个Deconv(+BN+ReLU) + 1x1conv,每个deconv上采样2倍,最终输出feature map大小为输入的$1/4$倍;
- 简单Decoder结构,双线性差值上采样$4$倍,然后是ReLU+3x3conv。
方案1非线性更高,因此在CNN的结构中使用比较多。ResNet系列在方案1上的结果远高于方案2,说明CNN结构的学习能力需要强有力的decoder来进一步加强。由于Transformer强大的学习能力,方案2这样的的简单decoder也能达到很高的精度。
实验采用姿态估计中Top-Down的方案,即先用一个检测器检测出单个人体框,然后用ViTPose对人体框进行姿态估计。第一步的检测器在COCO的val集上用的是SimpleBaseline,而在最后的COCO test-dev集上与SOTA方案的比较实验中,采用了Bigdet。SOTA结果是在576x432输入,采用1B参数量的ViTAE-G作为backbone,使用MS COCO + AI Challenger训练的情况下获得的。
2. ViTPose的特性
⚪ 预训练的灵活性
一般情况下backbone都需要ImageNet上预训练。本文提出了三种预训练方案:
- 采用ImageNet预训练分类任务,比较经典的方法,数据集总共1M图片
- 采用MS COCO预训练MAE任务,将$75\%$的patch随机mask掉,然后让网络学习恢复这些patch,数据集共150K图片
- 任务框架同方案2,不过数据集采用MS COCO + AI Challenger,共500K图片
由于ViTPose是单人检测模型,因此将MS COCO和AI Challenger中的单个人体crop出来,与ImageNet单个object的数据分布保持一致。然后在3个数据集上分别训练1600个epoch,再在MS COCO上fine tune 210个epoch。
采用VitPose-B结构,在MS COCO val set上,三种预训练方案的结果如下。可以看到使用MS COCO + AI Challenger,在只有一半数据量的情况下,可以达到比ImageNet更好的效果。
⚪ 分辨率的灵活性
ViTPose可以通过使用更大的输出尺寸来训练,也可以通过减小backbone中的下采样来构造更大尺度的feature map,这两种操作都能提高精度,具体如下:
- 更大尺寸的输入:直接缩放原始图像,得到对应大小的输入
- 更大尺寸的特征:降低采样倍数,修改patch层的stride参数
分辨率越大结果越高。
⚪ 注意力的灵活性
Transformer中的Attention的计算量是Feature map尺寸的平方,因此是很大的,而且显存占用也很大。因此作者用了Shift Window和Pooling Window两种方案来缓解这个问题。
⚪ 微调的灵活性
与NLP任务中一样,作者验证了只固定MHSA模块的参数,精度下降不多,而固定FFN的参数,则精度下降明显,因此作者认为MHSA更偏向与任务无关,而FFN则更具体任务关系更密切。
⚪ 多任务的灵活性
作者还尝试了采用同一个backbone,多个decoder,每个decoder对应一个数据集的任务,实验验证一次训练,多个数据集上的结果都能比较好,且比单个数据集精度有提升:
⚪ 蒸馏
作者提出了一个基于Transformer的蒸馏方法,与常见的用损失来监督Teacher和Student网络的思路不太一样,具体如下:
- 在大模型的patch embedding后的visual token后面增加一个知识token模块,并进行随机初始化
- 固定大模型的参数,只训练知识token模块
- 将训练好的知识token模块接到小模型的visual token后面,且固定知识token的参数,只训练小模型的其他参数
通过这样的流程,将所有的知识都融合到了知识token模块的参数里面,并且从大模型传递到小模型。