接上次说的的OpenPose的网络,该网络属于bottom-up
类型的网络,今天我们要说的是一种基于top-down
的网络AlphaPose
。该网络也是属于3年前的网络了,是上海交通大学发表的,借此机会希望记录下以便日后回顾。首先我们先给出链接地址:
文章:RMPE: Regional Multi-Person Pose Estimation
(目前有5.7k star)代码:AlphaPose
(AlphaPose是基于RMPE的部分算法开发的(poseNMS, PGPG)
)
一、知识背景
1.1 STN (在该代码中没有放入AlphaPose)
在我们说到原理之前需要科普下STN(Spatial Transfomer Networks)
网络, 该网络使用谷歌DeepMind2015年发表的文章。这里我们推荐可以看李宏毅老师的这门视频课程,简单易懂,自己还超喜欢听他的课程Spatial Transformer Network (STN)让 CNN 具有缩放/旋转不变性 李宏毅), 当然如果你觉得看视频太麻烦的话,你可以看下这篇博客详细解读Spatial Transformer Networks(STN)-一篇文章让你完全理解STN了该文章基本就是将上述视频进行了概述。
1.1.1 使用STN原因 -> CNN不具备完全的不变性
这里我总结下基于CNN其实并不具备scaling invariance
以及 rotation invariance
,只有maxpooling才具有不变性(invariation)若是2x2的池化,那么特征在2x2的区域中平移,得到的结果是一样的。越往后的pooling层,2x2的核的感受野就越大、所允许的平移也就越大。传统CNN中使用卷积和池化操做在必定程度上实现了平移不变性,但这种人工设定的变换规则使得网络过度的依赖先验知识,既不能真正实现平移不变性(不变性对于平移的要求很高),又使得CNN对于旋转,扭曲等未人为设定的几何变换缺少应有的特征不变性。所以提出了STN。简单理解CNN有微小的平移不变性,但是该不变性主要还是因为max-pooling的操作导致的
1.1.2 STN
STN说白了就是一个映射转换功能,通过该网络可以实现对原图的移动旋转缩放以及裁剪(这里裁剪先不考虑)。对于每一种变化方式都是有两个参数,最后我们会有6个参数(3
[移动+旋转+缩放] *
2
[参数])来进行对原图变化, 这里可以理解这里就是替代CNN不具备平移不变性的特征,这个部件可以放到CNN网络中的任意一个位置。STN相当于在传统的一层Convolution中间,装了一个“插件”,可以使得传统的卷积带有了[裁剪]、[平移]、[缩放]、[旋转]等特性
我们举一个简单的例子,比如我们的abcdef的值我们得到了,如下图所示。比如右边白色矩形框中间的索引是
[2,2]
我们就可以推出左边对应的索引[1,1]
。例子
上面的例子会很容易理解,但是如果我们中间的转移矩阵万一出现小数呢?如下所示
例子2
为此我们需要做
interpolation
,插值的方法,它是介于四个点中间。不能直接设置为周围四个点某一个点,这样不利于微分
。具体该值怎么算如下所示,可以理解为就是
与周围点距离乘上周围点的值
解决方案 上述说的STN如下所示,我们这里可以用黄色的菱形所示,它可以放到CNN任意一个地方。如下所示、
上面的图也是很多介绍STN管用的原理图,该图主要分为三个部分
①
Localization net
把feature map U作为输入,过连续若干层计算(如卷积、FC等),回归出参数θ,在我们的例子中就是一个[2,3]大小的6维仿射变换参数,用于下一步计算。
②
Grid generator
+ Sampler
上面介绍的Interpolation(插值计算)
下面我们来看下基于STN有什么效果。
示例1
示例2
示例3
在演示的过程中发现input无论怎么变化经过ST之后Output里面的数字几乎是很稳定不怎么发生变化的。
简单示例1上面表示的是经过4次ST我们将数字放大的效果。
简单示例2图片输入到两个STN会出现两个不一样的结果,比如不同的部位,在进行合成。
1.1.3 STN Torch代码
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
self.conv2_drop = nn.Dropout2d()
self.fc1 = nn.Linear(320, 50)
self.fc2 = nn.Linear(50, 10)
# Spatial transformer localization-network
self.localization = nn.Sequential(
nn.Conv2d(1, 8, kernel_size=7),
nn.MaxPool2d(2, stride=2),
nn.ReLU(True),
nn.Conv2d(8, 10, kernel_size=5),
nn.MaxPool2d(2, stride=2),
nn.ReLU(True)
)
# Regressor for the 3 * 2 affine matrix
self.fc_loc = nn.Sequential(
nn.Linear(10 * 3 * 3, 32),
nn.ReLU(True),
nn.Linear(32, 3 * 2)
)
# Initialize the weights/bias with identity transformation
self.fc_loc[2].weight.data.zero_()
self.fc_loc[2].bias.data.copy_(torch.tensor([1, 0, 0, 0, 1, 0], dtype=torch.float))
# Spatial transformer network forward function
def stn(self, x):
xs = self.localization(x)
xs = xs.view(-1, 10 * 3 * 3)
theta = self.fc_loc(xs)
theta = theta.view(-1, 2, 3)
grid = F.affine_grid(theta, x.size())
x = F.grid_sample(x, grid)
return x
def forward(self, x):
# transform the input
x = self.stn(x)
# Perform the usual forward pass
x = F.relu(F.max_pool2d(self.conv1(x), 2))
x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
x = x.view(-1, 320)
x = F.relu(self.fc1(x))
x = F.dropout(x, training=self.training)
x = self.fc2(x)
return F.log_softmax(x, dim=1)
model = Net().to(device)
1.2 PoseNMS
如上图所示如果一个人检测多个人体框的时候我们可以基于p-NMS(poseNMS)的方式进行解决。对于上述的问题我个人觉得目前检测器都以及进入如此之快,该方法实用性其实并不大,也就是说出现该问题的机会也是比较小的。
下面给出了P-NMS的方法(源: (原)人体姿态识别alphapose)
目标检测中的NMS大家应该都理解,其实他是通过IOU进行NMS筛选的,筛选重合率较大的,且保留置信度最大的框。这里的衡量标准就是基于
IOU
, 这里的PoseNMS
其实的衡量标准就是基于距离的度量。该距离 = 姿态距离 + 空间距离
。
1.3 PGPG (姿势引导建议发生器(PGPG):数据增强,产生训练样本)
步骤:
1 归一化姿态,使得所有躯干有归一化长度。
2 使用kmeans聚类对齐的姿态,并且聚类得到的中心形成atomic poses。
3 对有相同atomic poses的人,计算gt bbox和detected bbox的偏移。
4 偏移使用gt bbox进行归一化。
5 此时,偏移作为频率的分布,且固定数据为高斯混合分布。对于不同的atomic poses,有不同的高斯混合分布的参数。
实在写不下去了,稍微理解下去看最新paper了。😴
参考
[1] 详细解读Spatial Transformer Networks(STN)-一篇文章让你完全理解STN了
[2] Spatial Transformer Network (STN)让 CNN 具有缩放/旋转不变性 李宏毅)
[3] CNN网络中的不变性理解
[4] CNN的旋转不变性和pooling
[5] 目标检测之网络篇(2)【STN-空间变换网络】
[6] STN Tutorial
[7] (原)人体姿态识别alphapose
网友评论