Integral Human Pose Regression
一. 论文简介
这篇论文比较通俗易懂,这里随便说一下
-
non-differentiable
- 网络输出heatmap,我们得通过argmax获取坐标,这里是无法进行反向计算的。
-
quantization error
- heatmap得缩小计算,使用hourglass得到的heatmap是原图的1/4或1/8,那么我们的误差范围也就是四个或八个像素了。
-
resolution
- 直接回归坐标位置:原始论文做法,效果很差。
- 替换argmax,使得整个步骤可以积分。
-
example
使用本文的方法,去除one-hot编码。假设种类编码:(x=[0,1,2,3]) 分类网络输出(已经求取softmax):(out_a = [0.1,0.2,0.3,0.4]),正常做法直接argmax求取(index=3) 即可。现在我们使用期望去求:(out_b = x*out) ,得到的结果(out_c=[0,0.2,0.6,1.2]),求和得到最终结果:(2)。
发现一个问题,两种求解方法得到的结果不一致?
- 因为Loss求解方法不同,传统使用(out_a)直接计算,后者使用(out_c)计算。
- 期望和最大概率有所不同,期望会权衡其它值的存在,最大概率只考虑当下。
二. 代码计算
2.1 原始代码
import torch.nn.functional as F
import torch
from torch.autograd import Variable
import torch.nn as nn
import numpy as np
import os
def makeGaussian(height, width, sigma=3, center=None):
""" Make a square gaussian kernel.
size is the length of a side of the square
sigma is full-width-half-maximum, which
can be thought of as an effective radius.
"""
x = np.arange(0, width, 1, float)
y = np.arange(0, height, 1, float)[:, np.newaxis]
if center is None:
x0 = width // 2
y0 = height // 2
else:
x0 = center[0]
y0 = center[1]
return 10 * np.exp(-4 * np.log(2) * ((x - x0) ** 2 + (y - y0) ** 2) / sigma ** 2)
def generate_hm(height, width, joints, maxlenght):
""" Generate a full Heap Map for every joints in an array
Args:
height : Wanted Height for the Heat Map
width : Wanted Width for the Heat Map
joints : Array of Joints 15*2
maxlenght : Lenght of the Bounding Box
"""
num_joints = joints.shape[0]
hm = np.zeros((num_joints, height, width), dtype=np.float32)
for i in range(num_joints):
s = int(np.sqrt(maxlenght) * maxlenght * 10 / 4096) + 3
hm[i, :, :] = makeGaussian(height, width, sigma=s, center=(joints[i, 0], joints[i, 1]))
return hm
def generate_3d_integral_preds_tensor_init(heatmaps, num_joints, x_dim, y_dim):
assert isinstance(heatmaps, torch.Tensor)
'''
heatmap: [B, numJoint, H, W]
'''
heatmap = heatmaps.reshape((heatmaps.shape[0], 3, -1))
heatmap = F.softmax(heatmap, 2)
heatmaps = heatmaps.reshape((heatmaps.shape[0], num_joints, y_dim, x_dim))
accu_x = heatmaps.sum(dim=2) # [1, 2, x_dim]
accu_y = heatmaps.sum(dim=3)
accu_x = accu_x * torch.arange(x_dim).type(torch.cuda.FloatTensor)
accu_y = accu_y * torch.arange(y_dim).type(torch.cuda.FloatTensor)
accu_x = accu_x.sum(dim=2, keepdim=True)
accu_y = accu_y.sum(dim=2, keepdim=True)
return accu_x, accu_y
if __name__ == '__main__':
x = torch.from_numpy(np.array([[1,2,3,4],[1,2,3,4]])).type(torch.float32)
GT_xy = np.array([[10, 10], [3, 8], [16, 18]])
heatmap = generate_hm(64, 32, GT_xy, 64) # [numJoint, 64, 64]
heatmap = torch.unsqueeze(torch.from_numpy(heatmap), 0).cuda() # [1, numJoint, 64, 64]
x, y = generate_3d_integral_preds_tensor_init(heatmaps=heatmap, num_joints=3, x_dim=32, y_dim=64) #
2.2 修改代码
先使用softmax和后使用softmax计算的结果不同,且笔者修改的代码和输入值一样,不知道在训练中有多少差别
import torch.nn.functional as F
import torch
from torch.autograd import Variable
import torch.nn as nn
import numpy as np
import os
def makeGaussian(height, width, sigma=3, center=None):
""" Make a square gaussian kernel.
size is the length of a side of the square
sigma is full-width-half-maximum, which
can be thought of as an effective radius.
"""
x = np.arange(0, width, 1, float)
y = np.arange(0, height, 1, float)[:, np.newaxis]
if center is None:
x0 = width // 2
y0 = height // 2
else:
x0 = center[0]
y0 = center[1]
return 10 * np.exp(-4 * np.log(2) * ((x - x0) ** 2 + (y - y0) ** 2) / sigma ** 2)
def generate_hm(height, width, joints, maxlenght):
""" Generate a full Heap Map for every joints in an array
Args:
height : Wanted Height for the Heat Map
width : Wanted Width for the Heat Map
joints : Array of Joints 15*2
maxlenght : Lenght of the Bounding Box
"""
num_joints = joints.shape[0]
hm = np.zeros((num_joints, height, width), dtype=np.float32)
for i in range(num_joints):
s = int(np.sqrt(maxlenght) * maxlenght * 10 / 4096) + 3
hm[i, :, :] = makeGaussian(height, width, sigma=s, center=(joints[i, 0], joints[i, 1]))
return hm
def generate_3d_integral_preds_tensor_modify(heatmaps):
assert isinstance(heatmaps, torch.Tensor)
'''
heatmap: [B, numJoint, H, W]
'''
accu_x = heatmaps.sum(dim=2) # [1, 2, x_dim]
accu_y = heatmaps.sum(dim=3)
accu_x = F.softmax(accu_x, 2)
accu_y = F.softmax(accu_y, 2)
accu_x = accu_x * torch.arange(heatmaps.shape[-1]).type(torch.cuda.FloatTensor)
accu_y = accu_y * torch.arange(heatmaps.shape[-2]).type(torch.cuda.FloatTensor)
accu_x = accu_x.sum(dim=2, keepdim=True)
accu_y = accu_y.sum(dim=2, keepdim=True)
return accu_x, accu_y
if __name__ == '__main__':
x = torch.from_numpy(np.array([[1,2,3,4],[1,2,3,4]])).type(torch.float32)
GT_xy = np.array([[10, 10], [3, 8], [16, 18]])
heatmap = generate_hm(64, 32, GT_xy, 64) # [numJoint, 64, 64]
heatmap = torch.unsqueeze(torch.from_numpy(heatmap), 0).cuda() # [1, numJoint, 64, 64]
x, y = generate_3d_integral_preds_tensor_modify(heatmaps=heatmap) #
print("////")
三. 参考文献
- 文章已给出