Integral Human Pose Regression论文阅读


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\)

发现一个问题,两种求解方法得到的结果不一致?

  1. 因为Loss求解方法不同,传统使用\(out_a\)直接计算,后者使用\(out_c\)计算。
  2. 期望和最大概率有所不同,期望会权衡其它值的存在,最大概率只考虑当下。

二. 代码计算

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("////")

三. 参考文献

  • 文章已给出

猜你喜欢

转载自www.cnblogs.com/wjy-lulu/p/12891403.html