MMPose理解

Posted Arrow

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MMPose理解相关的知识,希望对你有一定的参考价值。

MMPose理解

1. MMPose是什么

  • MMPose 是一款基于 Pytorch 的姿态估计开源工具箱,是 OpenMMLab 项目的成员之一,包含了丰富的 2D 多人姿态估计、2D 手部姿态估计、2D 人脸关键点检测、133关键点全身人体姿态估计、动物关键点检测、服饰关键点检测等算法以及相关的组件和模块。
  • MMPose 由 8 个主要部分组成,apis、structures、datasets、codecs、models、engine、evaluation 和 visualization。
    • apis 提供用于模型推理的高级 API
    • structures 提供 bbox、keypoint 和 PoseDataSample 等数据结构
    • datasets 支持用于姿态估计的各种数据集
      • transforms 包含各种数据增强变换
    • codecs 提供姿态编解码器:编码器用于将姿态信息(通常为关键点坐标)编码为模型学习目标(如热力图),解码器则用于将模型输出解码为姿态估计结果
    • models 以模块化结构提供了姿态估计模型的各类组件
      • pose_estimators 定义了所有姿态估计模型类
      • data_preprocessors 用于预处理模型的输入数据
      • backbones 包含各种骨干网络
      • necks 包含各种模型颈部组件
      • heads 包含各种模型头部
      • losses 包含各种损失函数
    • engine 包含与姿态估计任务相关的运行时组件
      • hooks 提供运行时的各种钩子
    • evaluation 提供各种评估模型性能的指标
    • visualization 用于可视化关键点骨架和热力图等信息

2. 编解码器

  • 在关键点检测任务中,根据算法的不同,需要利用标注信息,生成不同格式的训练目标,比如归一化的坐标值、一维向量、高斯热图等。同样的,对于模型输出的结果,也需要经过处理转换成标注信息格式。我们一般将标注信息到训练目标的处理过程称为编码,模型输出到标注信息的处理过程称为解码
  • 编码和解码是一对紧密相关的互逆处理过程。在 MMPose 早期版本中,编码和解码过程往往分散在不同模块里,使其不够直观和统一,增加了学习和维护成本。
  • MMPose 1.0 中引入了新模块编解码器(Codec) ,将关键点数据的编码和解码过程进行集成,以增加代码的友好度和复用性。
  • 编解码器在工作流程中所处的位置如下所示:
  • 一个编解码器主要包含两个部分:
    • 编码器
    • 解码器

2.1 编码器

  • 编码器主要负责将处于输入图片尺度的坐标值,编码为模型训练所需要的目标格式,主要包括:
    • 归一化的坐标值:用于 Regression-based 方法
    • 一维向量:用于 SimCC-based 方法
    • 高斯热图:用于 Heatmap-based 方法
  • 以 Regression-based 方法的编码器为例:
@abstractmethod
def encode(
    self,
    keypoints: np.ndarray,
    keypoints_visible: Optional[np.ndarray] = None
) -> Tuple[np.ndarray, np.ndarray]:
    """Encoding keypoints from input image space to normalized space.

    Args:
        keypoints (np.ndarray): Keypoint coordinates in shape (N, K, D)
        keypoints_visible (np.ndarray): Keypoint visibilities in shape
            (N, K)

    Returns:
        tuple:
        - reg_labels (np.ndarray): The normalized regression labels in
            shape (N, K, D) where D is 2 for 2d coordinates
        - keypoint_weights (np.ndarray): The target weights in shape
            (N, K)
    """

    if keypoints_visible is None:
        keypoints_visible = np.ones(keypoints.shape[:2], dtype=np.float32)

    w, h = self.input_size
    valid = ((keypoints >= 0) &
             (keypoints <= [w - 1, h - 1])).all(axis=-1) & (
                 keypoints_visible > 0.5)

    reg_labels = (keypoints / np.array([w, h])).astype(np.float32)
    keypoint_weights = np.where(valid, 1., 0.).astype(np.float32)

    return reg_labels, keypoint_weights
  • 参数说明
    • N:instance number
    • K:keypoint number
    • D:keypoint dimension
    • L:embedding tag dimension
    • [w, h]:image size
    • [W, H]:heatmap size
    • sigma:The sigma value of the Gaussian heatmap

2.1.1 Heatmap-based

  • Heatmap-based方法为每个关节生成似然热图(likelihood heatmap),并使用argmax 或 soft-argmax 操作把关节定位到一个点。
  • 2D heatmap生成为一个二维高斯分布,其中心为标注的关节位置,通过为每个位置分配概率值来抑制false positive并平滑训练过程。
  • heatmap的不足
    • 计算量大
    • 存储量大
    • 扩展到3D或4D(空间+时间)成本高
    • 难以把heatmap布署到one-state方法中
    • 低分辨率输入的性能受到限制
    • 为了提高特征图分辨率以获得更高的定位精度,需要多个计算量大的上采样层
    • 为减少量化误差,需采用额外的后处理

2.1.2 RLE ( Regression-based)

  • RLE:Residual Log-likelihood Estimation (残差对数似然估计)
  • DLE:Direct Likelihood Estimation
  • RLE是一种regression-based的方法。 具体来说,RLE 学习分布的变化而不是未参考的基础分布,以促进训练过程。
  • RLE的优势:其性能和计算量均优于heatmap-based方法

  • 标准Regression-based方法直接将输入映射到输出关节坐标,这对于各种人体姿态估计任务和实时应用来说是灵活高效的,尤其是在边缘设备上。一个标准的热图头(3 个反卷积层)的成本是 ResNet-50 主干的 1.4 倍 FLOP,而回归头仅花费相同主干的 1/20000 FLOP。
  • 标准Regression-based的不足
    • 回归的性能较差
    • 在遮挡、运动模糊和截断等具有挑战性的情况下,真实标签本质上是模棱两可的。通过利用似然热图,基于热图的方法对这些歧义具有鲁棒性。 但是RLE之前的回归方法容易受到这些嘈杂标签的影响。


2.1.3 SimCC (SimCC-based )

  • SimCC:Simple Coordinate Classification
  • 思路:SimCC将 HPE(Human Poes Estimation) 重新定义为水平和垂直坐标的两个分类任务。将每个像素均匀地划分为多个 bin,从而实现亚像素定位精度和低量化误差。
  • 方法比较

2.2 解码器

  • 解码器主要负责将模型的输出解码为输入图片尺度的坐标值,处理过程与编码器相反。
  • 以 Regression-based 方法的解码器为例:
def decode(self, encoded: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
    """Decode keypoint coordinates from normalized space to input image
    space.

    Args:
        encoded (np.ndarray): Coordinates in shape (N, K, D)

    Returns:
        tuple:
        - keypoints (np.ndarray): Decoded coordinates in shape (N, K, D)
        - scores (np.ndarray): The keypoint scores in shape (N, K).
            It usually represents the confidence of the keypoint prediction

    """

    if encoded.shape[-1] == 2:
        N, K, _ = encoded.shape
        normalized_coords = encoded.copy()
        scores = np.ones((N, K), dtype=np.float32)
    elif encoded.shape[-1] == 4:
        # split coords and sigma if outputs contain output_sigma
        normalized_coords = encoded[..., :2].copy()
        output_sigma = encoded[..., 2:4].copy()
        scores = (1 - output_sigma).mean(axis=-1)
    else:
        raise ValueError(
            'Keypoint dimension should be 2 or 4 (with sigma), '
            f'but got encoded.shape[-1]')

    w, h = self.input_size
    keypoints = normalized_coords * np.array([w, h])

    return keypoints, scores
  • 默认情况下,decode() 方法只提供单个目标数据的解码过程,你也可以通过 batch_decode() 来实现批量解码提升执行效率。

2.3 常见用法

  • 在 MMPose 配置文件中,主要有三处涉及编解码器:
    • 定义编解码器
    • 生成训练目标
    • 模型头部

2.3.1 定义编解码器

  • 以回归方法生成归一化的坐标值为例,在配置文件中,我们通过如下方式定义编解码器:
codec = dict(type='RegressionLabel', input_size=(192, 256))

2.3.2 生成训练目标

  • 在数据处理阶段生成训练目标时,需要传入编解码器用于编码:
dict(type='GenerateTarget', target_type='keypoint_label', encoder=codec)

2.3.3 模型头部

  • 在 MMPose 中,我们在模型头部对模型的输出进行解码,需要传入编解码器用于解码:
head=dict(
    type='RLEHead',
    in_channels=2048,
    num_joints=17,
    loss=dict(type='RLELoss', use_target_weight=True),
    decoder=codec
)

以上是关于MMPose理解的主要内容,如果未能解决你的问题,请参考以下文章

姿态分析开源工具箱MMPose使用示例:人体姿势估计

姿态分析开源工具箱MMPose使用示例:2d手势估计

姿态分析开源工具箱MMPose安装及使用示例(2d face landmark detection)

MMPose

human pose estimation

安装Open-MMlab 的 MMPose 和 MMCV