Transformers 文档
ViTPose
并获取增强的文档体验
开始使用
ViTPose
概述
ViTPose 模型由 Yufei Xu、Jing Zhang、Qiming Zhang、Dacheng Tao 在 ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation 中提出。ViTPose 采用标准的、非分层的 Vision Transformer 作为人体关键点估计任务的骨干网络。在其之上添加了一个简单的解码器头,用于从给定的图像预测热图。尽管其结构简单,但该模型在具有挑战性的 MS COCO 关键点检测基准测试中取得了最先进的结果。在 ViTPose++: Vision Transformer for Generic Body Pose Estimation 中,作者在 ViT 骨干网络中采用混合专家 (MoE) 模块,并在更多数据上进行预训练,进一步提高了性能,模型得到了进一步改进。
论文摘要如下
尽管在设计中没有考虑特定的领域知识,但纯视觉 Transformer 在视觉识别任务中表现出了出色的性能。然而,在揭示这种简单结构在姿态估计任务中的潜力方面,人们几乎没有付出努力。在本文中,我们通过一个名为 ViTPose 的简单基线模型,从模型结构的简洁性、模型尺寸的可扩展性、训练范例的灵活性以及模型之间知识的可迁移性等各个方面,展示了纯视觉 Transformer 在姿态估计方面的惊人能力。具体而言,ViTPose 采用纯粹的非分层视觉 Transformer 作为骨干网络,为给定的人体实例提取特征,并采用轻量级解码器进行姿态估计。通过利用 Transformer 的可扩展模型容量和高并行性,它可以从 1 亿参数扩展到 10 亿参数,在吞吐量和性能之间设定了新的帕累托前沿。此外,ViTPose 在注意力类型、输入分辨率、预训练和微调策略以及处理多姿态任务方面非常灵活。我们还通过经验证明,大型 ViTPose 模型的知识可以通过简单的知识令牌轻松转移到小型模型。实验结果表明,我们的基本 ViTPose 模型在具有挑战性的 MS COCO 关键点检测基准测试中优于代表性方法,而最大的模型则创造了新的最先进水平。

此模型由 nielsr 和 sangbumchoi 贡献。原始代码可以在这里找到。
使用技巧
ViTPose 是一种所谓的自上而下的关键点检测模型。这意味着首先使用对象检测器(如 RT-DETR)来检测图像中的人物(或其他实例)。接下来,ViTPose 将裁剪后的图像作为输入,并预测每个图像的关键点。
import torch
import requests
import numpy as np
from PIL import Image
from transformers import AutoProcessor, RTDetrForObjectDetection, VitPoseForPoseEstimation
device = "cuda" if torch.cuda.is_available() else "cpu"
url = "http://images.cocodataset.org/val2017/000000000139.jpg"
image = Image.open(requests.get(url, stream=True).raw)
# ------------------------------------------------------------------------
# Stage 1. Detect humans on the image
# ------------------------------------------------------------------------
# You can choose any detector of your choice
person_image_processor = AutoProcessor.from_pretrained("PekingU/rtdetr_r50vd_coco_o365")
person_model = RTDetrForObjectDetection.from_pretrained("PekingU/rtdetr_r50vd_coco_o365", device_map=device)
inputs = person_image_processor(images=image, return_tensors="pt").to(device)
with torch.no_grad():
outputs = person_model(**inputs)
results = person_image_processor.post_process_object_detection(
outputs, target_sizes=torch.tensor([(image.height, image.width)]), threshold=0.3
)
result = results[0] # take first image results
# Human label refers 0 index in COCO dataset
person_boxes = result["boxes"][result["labels"] == 0]
person_boxes = person_boxes.cpu().numpy()
# Convert boxes from VOC (x1, y1, x2, y2) to COCO (x1, y1, w, h) format
person_boxes[:, 2] = person_boxes[:, 2] - person_boxes[:, 0]
person_boxes[:, 3] = person_boxes[:, 3] - person_boxes[:, 1]
# ------------------------------------------------------------------------
# Stage 2. Detect keypoints for each person found
# ------------------------------------------------------------------------
image_processor = AutoProcessor.from_pretrained("usyd-community/vitpose-base-simple")
model = VitPoseForPoseEstimation.from_pretrained("usyd-community/vitpose-base-simple", device_map=device)
inputs = image_processor(image, boxes=[person_boxes], return_tensors="pt").to(device)
with torch.no_grad():
outputs = model(**inputs)
pose_results = image_processor.post_process_pose_estimation(outputs, boxes=[person_boxes])
image_pose_result = pose_results[0] # results for first image
ViTPose++ 模型
最好的检查点是 ViTPose++ 论文中的那些。ViTPose++ 模型为 ViT 骨干网络采用了所谓的 混合专家 (MoE) 架构,从而获得更好的性能。
ViTPose+ 检查点使用 6 个专家,因此可以传递 6 个不同的数据集索引。下面提供了各种数据集索引的概述
- 0: COCO validation 2017 数据集,使用在“person”类上获得 56 AP 的对象检测器
- 1: AiC 数据集
- 2: MPII 数据集
- 3: AP-10K 数据集
- 4: APT-36K 数据集
- 5: COCO-WholeBody 数据集
在模型的前向传播中传递 dataset_index
参数,以指示要为批次中的每个示例使用哪些专家。下面显示了示例用法
image_processor = AutoProcessor.from_pretrained("usyd-community/vitpose-plus-base")
model = VitPoseForPoseEstimation.from_pretrained("usyd-community/vitpose-plus-base", device=device)
inputs = image_processor(image, boxes=[person_boxes], return_tensors="pt").to(device)
dataset_index = torch.tensor([0], device=device) # must be a tensor of shape (batch_size,)
with torch.no_grad():
outputs = model(**inputs, dataset_index=dataset_index)
ViTPose+ 检查点使用 6 个专家,因此可以传递 6 个不同的数据集索引。下面提供了各种数据集索引的概述
- 0: COCO validation 2017 数据集,使用在“person”类上获得 56 AP 的对象检测器
- 1: AiC 数据集
- 2: MPII 数据集
- 3: AP-10K 数据集
- 4: APT-36K 数据集
- 5: COCO-WholeBody 数据集
可视化
要可视化各种关键点,可以使用 supervision
库(需要 pip install supervision
)
import supervision as sv
xy = torch.stack([pose_result['keypoints'] for pose_result in image_pose_result]).cpu().numpy()
scores = torch.stack([pose_result['scores'] for pose_result in image_pose_result]).cpu().numpy()
key_points = sv.KeyPoints(
xy=xy, confidence=scores
)
edge_annotator = sv.EdgeAnnotator(
color=sv.Color.GREEN,
thickness=1
)
vertex_annotator = sv.VertexAnnotator(
color=sv.Color.RED,
radius=2
)
annotated_frame = edge_annotator.annotate(
scene=image.copy(),
key_points=key_points
)
annotated_frame = vertex_annotator.annotate(
scene=annotated_frame,
key_points=key_points
)
或者,也可以使用 OpenCV 可视化关键点(需要 pip install opencv-python
)
import math
import cv2
def draw_points(image, keypoints, scores, pose_keypoint_color, keypoint_score_threshold, radius, show_keypoint_weight):
if pose_keypoint_color is not None:
assert len(pose_keypoint_color) == len(keypoints)
for kid, (kpt, kpt_score) in enumerate(zip(keypoints, scores)):
x_coord, y_coord = int(kpt[0]), int(kpt[1])
if kpt_score > keypoint_score_threshold:
color = tuple(int(c) for c in pose_keypoint_color[kid])
if show_keypoint_weight:
cv2.circle(image, (int(x_coord), int(y_coord)), radius, color, -1)
transparency = max(0, min(1, kpt_score))
cv2.addWeighted(image, transparency, image, 1 - transparency, 0, dst=image)
else:
cv2.circle(image, (int(x_coord), int(y_coord)), radius, color, -1)
def draw_links(image, keypoints, scores, keypoint_edges, link_colors, keypoint_score_threshold, thickness, show_keypoint_weight, stick_width = 2):
height, width, _ = image.shape
if keypoint_edges is not None and link_colors is not None:
assert len(link_colors) == len(keypoint_edges)
for sk_id, sk in enumerate(keypoint_edges):
x1, y1, score1 = (int(keypoints[sk[0], 0]), int(keypoints[sk[0], 1]), scores[sk[0]])
x2, y2, score2 = (int(keypoints[sk[1], 0]), int(keypoints[sk[1], 1]), scores[sk[1]])
if (
x1 > 0
and x1 < width
and y1 > 0
and y1 < height
and x2 > 0
and x2 < width
and y2 > 0
and y2 < height
and score1 > keypoint_score_threshold
and score2 > keypoint_score_threshold
):
color = tuple(int(c) for c in link_colors[sk_id])
if show_keypoint_weight:
X = (x1, x2)
Y = (y1, y2)
mean_x = np.mean(X)
mean_y = np.mean(Y)
length = ((Y[0] - Y[1]) ** 2 + (X[0] - X[1]) ** 2) ** 0.5
angle = math.degrees(math.atan2(Y[0] - Y[1], X[0] - X[1]))
polygon = cv2.ellipse2Poly(
(int(mean_x), int(mean_y)), (int(length / 2), int(stick_width)), int(angle), 0, 360, 1
)
cv2.fillConvexPoly(image, polygon, color)
transparency = max(0, min(1, 0.5 * (keypoints[sk[0], 2] + keypoints[sk[1], 2])))
cv2.addWeighted(image, transparency, image, 1 - transparency, 0, dst=image)
else:
cv2.line(image, (x1, y1), (x2, y2), color, thickness=thickness)
# Note: keypoint_edges and color palette are dataset-specific
keypoint_edges = model.config.edges
palette = np.array(
[
[255, 128, 0],
[255, 153, 51],
[255, 178, 102],
[230, 230, 0],
[255, 153, 255],
[153, 204, 255],
[255, 102, 255],
[255, 51, 255],
[102, 178, 255],
[51, 153, 255],
[255, 153, 153],
[255, 102, 102],
[255, 51, 51],
[153, 255, 153],
[102, 255, 102],
[51, 255, 51],
[0, 255, 0],
[0, 0, 255],
[255, 0, 0],
[255, 255, 255],
]
)
link_colors = palette[[0, 0, 0, 0, 7, 7, 7, 9, 9, 9, 9, 9, 16, 16, 16, 16, 16, 16, 16]]
keypoint_colors = palette[[16, 16, 16, 16, 16, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0]]
numpy_image = np.array(image)
for pose_result in image_pose_result:
scores = np.array(pose_result["scores"])
keypoints = np.array(pose_result["keypoints"])
# draw each point on image
draw_points(numpy_image, keypoints, scores, keypoint_colors, keypoint_score_threshold=0.3, radius=4, show_keypoint_weight=False)
# draw links
draw_links(numpy_image, keypoints, scores, keypoint_edges, link_colors, keypoint_score_threshold=0.3, thickness=1, show_keypoint_weight=False)
pose_image = Image.fromarray(numpy_image)
pose_image

资源
以下是官方 Hugging Face 和社区(🌎 表示)资源列表,可帮助您开始使用 ViTPose。如果您有兴趣提交资源以包含在此处,请随时打开 Pull Request,我们将进行审核!该资源最好能展示一些新的东西,而不是重复现有资源。
VitPoseImageProcessor
class transformers.VitPoseImageProcessor
< source >( do_affine_transform: bool = True size: typing.Dict[str, int] = None do_rescale: bool = True rescale_factor: typing.Union[int, float] = 0.00392156862745098 do_normalize: bool = True image_mean: typing.Union[float, typing.List[float], NoneType] = None image_std: typing.Union[float, typing.List[float], NoneType] = None **kwargs )
参数
- do_affine_transform (
bool
, 可选, 默认为True
) — 是否对输入图像应用仿射变换。 - size (
Dict[str, int]
可选, 默认为{"height" -- 256, "width": 192}
): 应用affine_transform
后图像的分辨率。仅在do_affine_transform
设置为True
时生效。可以被preprocess
方法中的size
覆盖。 - do_rescale (
bool
, 可选, 默认为True
) — 是否应用缩放因子(使像素值变为 0. 和 1. 之间的浮点数)。 - rescale_factor (
int
或float
, 可选, 默认为1/255
) — 如果要缩放图像,则使用的缩放因子。可以被preprocess
方法中的rescale_factor
覆盖。 - do_normalize (
bool
, 可选, 默认为True
) — 是否使用均值和标准差对输入进行归一化。 - image_mean (
List[int]
, 默认为[0.485, 0.456, 0.406]
, 可选) — 用于归一化图像时,每个通道的均值序列。 - image_std (
List[int]
, 默认为[0.229, 0.224, 0.225]
, 可选) — 用于归一化图像时,每个通道的标准差序列。
构建 VitPose 图像处理器。
preprocess
< source >( images: typing.Union[ForwardRef('PIL.Image.Image'), numpy.ndarray, ForwardRef('torch.Tensor'), list['PIL.Image.Image'], list[numpy.ndarray], list['torch.Tensor']] boxes: typing.Union[typing.List[typing.List[float]], numpy.ndarray] do_affine_transform: bool = None size: typing.Dict[str, int] = None do_rescale: bool = None rescale_factor: float = None do_normalize: bool = None image_mean: typing.Union[float, typing.List[float], NoneType] = None image_std: typing.Union[float, typing.List[float], NoneType] = None return_tensors: typing.Union[str, transformers.utils.generic.TensorType, NoneType] = None data_format: typing.Union[str, transformers.image_utils.ChannelDimension] = <ChannelDimension.FIRST: 'channels_first'> input_data_format: typing.Union[str, transformers.image_utils.ChannelDimension, NoneType] = None ) → BatchFeature
参数
- images (
ImageInput
) — 要预处理的图像。 期望是像素值范围从 0 到 255 的单张或批量图像。如果传入像素值在 0 到 1 之间的图像,请设置do_rescale=False
。 - boxes (
List[List[List[float]]]
或np.ndarray
) — 每张图像的边界框列表或数组。每个框应为一个包含 4 个浮点数的列表,表示 COCO 格式的边界框坐标(top_left_x,top_left_y,宽度,高度)。 - do_affine_transform (
bool
, 可选, 默认为self.do_affine_transform
) — 是否对输入图像应用仿射变换。 - size (
Dict[str, int]
可选, 默认为self.size
) — 字典格式为{"height": h, "width": w}
,指定调整大小后输出图像的尺寸。 - do_rescale (
bool
, 可选, 默认为self.do_rescale
) — 是否将图像值缩放到 [0 - 1] 之间。 - rescale_factor (
float
, 可选, 默认为self.rescale_factor
) — 如果do_rescale
设置为True
,则用于缩放图像的缩放因子。 - do_normalize (
bool
, 可选, 默认为self.do_normalize
) — 是否对图像进行归一化。 - image_mean (
float
或List[float]
, 可选, 默认为self.image_mean
) — 如果do_normalize
设置为True
,则使用的图像均值。 - image_std (
float
或List[float]
, 可选, 默认为self.image_std
) — 如果do_normalize
设置为True
,则使用的图像标准差。 - return_tensors (
str
或 TensorType, 可选, 默认为'np'
) — 如果设置,将返回特定框架的张量。可接受的值为:'tf'
:返回 TensorFlowtf.constant
对象。'pt'
:返回 PyTorchtorch.Tensor
对象。'np'
:返回 NumPynp.ndarray
对象。'jax'
:返回 JAXjnp.ndarray
对象。
返回
一个 BatchFeature,包含以下字段
- pixel_values — 要馈送到模型的像素值,形状为 (batch_size, num_channels, height, width)。
预处理单张或批量图像。
post_process_pose_estimation
< source >( outputs: VitPoseEstimatorOutput boxes: typing.Union[typing.List[typing.List[typing.List[float]]], numpy.ndarray] kernel_size: int = 11 threshold: float = None target_sizes: typing.Union[transformers.utils.generic.TensorType, typing.List[typing.Tuple]] = None ) → List[List[Dict]]
参数
- outputs (
VitPoseEstimatorOutput
) — VitPoseForPoseEstimation 模型输出。 - boxes (
List[List[List[float]]]
或np.ndarray
) — 每张图像的边界框列表或数组。每个框应为一个包含 4 个浮点数的列表,表示 COCO 格式的边界框坐标(top_left_x,top_left_y,宽度,高度)。 - kernel_size (
int
, 可选, 默认为 11) — 用于调制的高斯核大小 (K)。 - threshold (
float
, 可选, 默认为 None) — 保留对象检测预测的分数阈值。 - target_sizes (
torch.Tensor
或List[Tuple[int, int]]
, 可选) — 形状为(batch_size, 2)
的张量或元组列表 (Tuple[int, int]
),包含批次中每张图像的目标尺寸(height, width)
。 如果未设置,预测将使用默认值调整大小。
返回
List[List[Dict]]
字典列表,每个字典包含模型预测的批次中图像的关键点和框。
将热图转换为关键点预测,然后将其转换回图像。
VitPoseConfig
class transformers.VitPoseConfig
< source >( backbone_config: PretrainedConfig = None backbone: str = None use_pretrained_backbone: bool = False use_timm_backbone: bool = False backbone_kwargs: dict = None initializer_range: float = 0.02 scale_factor: int = 4 use_simple_decoder: bool = True **kwargs )
参数
- backbone_config (
PretrainedConfig
或dict
, 可选, 默认为VitPoseBackboneConfig()
) — 主干模型的配置。目前,仅支持model_type
为vitpose_backbone
的backbone_config
。 - backbone (
str
, 可选) — 当backbone_config
为None
时,要使用的主干网络的名称。如果use_pretrained_backbone
为True
,这将从 timm 或 transformers 库加载相应的预训练权重。如果use_pretrained_backbone
为False
,这将加载主干网络的配置,并使用该配置以随机权重初始化主干网络。 - use_pretrained_backbone (
bool
, 可选, 默认为False
) — 是否使用主干网络的预训练权重。 - use_timm_backbone (
bool
, 可选, 默认为False
) — 是否从 timm 库加载backbone
。如果为False
,则从 transformers 库加载主干网络。 - backbone_kwargs (
dict
, 可选) — 从检查点加载时要传递给 AutoBackbone 的关键字参数,例如{'out_indices': (0, 1, 2, 3)}
。如果设置了backbone_config
,则无法指定此项。 - initializer_range (
float
, 可选, 默认为 0.02) — 用于初始化所有权重矩阵的 truncated_normal_initializer 的标准差。 - scale_factor (
int
, 可选, 默认为 4) — 用于放大来自 ViT 主干网络的特征图的因子。 - use_simple_decoder (
bool
, 可选, 默认为True
) — 是否使用VitPoseSimpleDecoder
将来自主干网络的特征图解码为热图。否则,将使用VitPoseClassicDecoder
。
这是用于存储 VitPoseForPoseEstimation 配置的配置类。它用于根据指定的参数实例化 VitPose 模型,定义模型架构。使用默认值实例化配置将产生与 VitPose usyd-community/vitpose-base-simple 架构类似的配置。
配置对象继承自 PretrainedConfig,可用于控制模型输出。有关更多信息,请阅读 PretrainedConfig 的文档。
示例
>>> from transformers import VitPoseConfig, VitPoseForPoseEstimation
>>> # Initializing a VitPose configuration
>>> configuration = VitPoseConfig()
>>> # Initializing a model (with random weights) from the configuration
>>> model = VitPoseForPoseEstimation(configuration)
>>> # Accessing the model configuration
>>> configuration = model.config
VitPoseForPoseEstimation
class transformers.VitPoseForPoseEstimation
< source >( config: VitPoseConfig )
参数
- config (VitPoseConfig) — 具有模型所有参数的模型配置类。使用配置文件初始化不会加载与模型关联的权重,仅加载配置。查看 from_pretrained() 方法以加载模型权重。
带有姿势估计头的 VitPose 模型。此模型是 PyTorch torch.nn.Module 子类。将其用作常规 PyTorch 模块,并查阅 PyTorch 文档以了解与常规用法和行为相关的所有事项。
forward
< source >( pixel_values: Tensor dataset_index: typing.Optional[torch.Tensor] = None flip_pairs: typing.Optional[torch.Tensor] = None labels: typing.Optional[torch.Tensor] = None output_attentions: typing.Optional[bool] = None output_hidden_states: typing.Optional[bool] = None return_dict: typing.Optional[bool] = None ) → transformers.models.vitpose.modeling_vitpose.VitPoseEstimatorOutput
或 tuple(torch.FloatTensor)
参数
- pixel_values (
torch.FloatTensor
,形状为(batch_size, num_channels, height, width)
) — 像素值。像素值可以使用 VitPoseImageProcessor 获得。 有关详细信息,请参阅 VitPoseImageProcessor.call()。 - dataset_index (
torch.Tensor
,形状为(batch_size,)
) — 用于主干网络的混合专家 (MoE) 块的索引。这对应于训练期间使用的数据集索引,例如,对于单个数据集索引 0 指的是相应的数据集。对于多个数据集索引 0 指的是数据集 A(例如 MPII),索引 1 指的是数据集 B(例如 CrowdPose)。
- flip_pairs (
torch.tensor
, 可选) — 是否镜像关键点对(例如,左耳 — 右耳)。 - output_attentions (
bool
, 可选) — 是否返回所有注意力层的注意力张量。 有关更多详细信息,请参阅返回张量下的attentions
。 - output_hidden_states (
bool
, 可选) — 是否返回所有层的隐藏状态。 有关更多详细信息,请参阅返回张量下的hidden_states
。 - return_dict (
bool
, 可选) — 是否返回 ModelOutput 而不是普通元组。
返回
transformers.models.vitpose.modeling_vitpose.VitPoseEstimatorOutput
或 tuple(torch.FloatTensor)
一个 transformers.models.vitpose.modeling_vitpose.VitPoseEstimatorOutput
或 torch.FloatTensor
的元组(如果传递了 return_dict=False
或当 config.return_dict=False
时),其中包括各种元素,具体取决于配置 (VitPoseConfig) 和输入。
-
loss (
torch.FloatTensor
,形状为(1,)
,可选,当提供labels
时返回) — 目前不支持损失。 有关更多详细信息,请参阅 https://github.com/ViTAE-Transformer/ViTPose/tree/main/mmpose/models/losses。 -
heatmaps (
torch.FloatTensor
,形状为(batch_size, num_keypoints, height, width)
) — 模型预测的热图。 -
hidden_states (
tuple(torch.FloatTensor)
, 可选, 当传递output_hidden_states=True
或当config.output_hidden_states=True
时返回) —torch.FloatTensor
的元组(如果模型具有嵌入层,则为嵌入的输出 + 每个阶段的输出),形状为(batch_size, sequence_length, hidden_size)
。 模型在每个阶段输出的隐藏状态(也称为特征图)。 -
attentions (
tuple(torch.FloatTensor)
, 可选, 当传递output_attentions=True
或当config.output_attentions=True
时返回) —torch.FloatTensor
的元组(每层一个),形状为(batch_size, num_heads, patch_size, sequence_length)
。注意力 softmax 之后的注意力权重,用于计算自注意力头中的加权平均值。
VitPoseForPoseEstimation 的 forward 方法覆盖了 __call__
特殊方法。
虽然 forward 传递的配方需要在该函数中定义,但应该在之后调用 Module
实例而不是此函数,因为前者负责运行预处理和后处理步骤,而后者则会默默地忽略它们。
示例
>>> from transformers import AutoImageProcessor, VitPoseForPoseEstimation
>>> import torch
>>> from PIL import Image
>>> import requests
>>> processor = AutoImageProcessor.from_pretrained("usyd-community/vitpose-base-simple")
>>> model = VitPoseForPoseEstimation.from_pretrained("usyd-community/vitpose-base-simple")
>>> url = "http://images.cocodataset.org/val2017/000000039769.jpg"
>>> image = Image.open(requests.get(url, stream=True).raw)
>>> boxes = [[[412.8, 157.61, 53.05, 138.01], [384.43, 172.21, 15.12, 35.74]]]
>>> inputs = processor(image, boxes=boxes, return_tensors="pt")
>>> with torch.no_grad():
... outputs = model(**inputs)
>>> heatmaps = outputs.heatmaps