RTMW-m (whole-body pose, 133 keypoints) β€” ExecuTorch

rtmw_m_xnnpack_fp32.pte (129.1 MB)

  • Source: mmpose RTMW, rtmw-dw-l-m_simcc-cocktail14_270e-256x192 (the m-size distilled build)
  • License: Apache-2.0
  • Input: [1, 3, 256, 192], a crop around one person, ImageNet-normalised
  • Output: two SimCC maps, [1, 133, 384] and [1, 133, 512] β€” the x and y bins for each keypoint at a split ratio of 2.0

Body, feet, face and both hands in one pass. The shelf's four RTMPose variants each cover one of those; this covers all of them, which is the whole reason to carry a model this size next to a 21.9 MB body-only one.

Top-down: it expects a box around a person, not a scene. Pair it with a detector β€” the shelf has YOLOX-s.

Verification (Mac arm64, 2026-08-23)

XNNPACK fp32: 17.0 ms against 178.9 ms eager, worst corr 1.000000, 129.1 MB.

Correlation is measured on random input, so the check that matters here is decoded coordinates on real person crops β€” 133 keypoints across five crops, 665 measurements, against eager on the same tensor:

build mean apart over 2 px over 10 px worst
XNNPACK fp32 0.001 px 0 0 0.5 px
XNNPACK fp16 0.414 px 4 2 123 px
Core ML 1.199 px 54 4 124.5 px

fp32 is exact on four of the five crops; the one difference is half a pixel, which is a single SimCC bin.

A worst of 123 px on a 192-wide crop looks alarming and is worth reading with the count beside it: for fp16 that is 4 of 665 keypoints, and those four had the lowest peak activations in eager's own output (median summed peak 0.39). SimCC picks a bin by argmax, so a keypoint the model is unsure about flips to a distant bin under any numeric change. Core ML moves 54 of 665, which is a different matter.

Not shipped, and why

  • fp16: 127.9 MB against 129.1, and 54.2 ms against 17.0 β€” three times slower for no size gain. The keypoint agreement above is good; there is simply nothing to buy.
  • Core ML: worst corr 0.920, below the 0.995 gate, and 54 of 665 keypoints move.
  • int8: does not export. PT2E quantization fails with ValueError: getitem_6 is not an aten adaptive_avg_pool2d operator β€” the quantizer's pattern match against CSPNeXt's channel attention, reached through the PAFPN's tuple output. The RTMPose variants on this shelf have no int8 either, though those failed on quality rather than at export.

Conversion

CONVERT_REPOS=<dir containing mmpose> python convert/export_rtmw.py fp32
CONVERT_REPOS=<dir containing mmpose> python convert/check_rtmw.py

RTMW is not another entry in export_rtmpose.py's variant table: RTMPose feeds the backbone's last stage straight to the head, RTMW puts a CSPNeXtPAFPN neck in between and uses RTMWHead. The widths and sizes are read off mmpose's own rtmw-m_8xb1024-270e_cocktail14-256x192.py, and a strict load_state_dict is what proves they match the checkpoint. mmpose needs mmengine and mmcv-lite; xtcocotools, mmdet and mmcv._ext are imported at module scope and never called on this path, so they are stubbed.

Feed it contiguous tensors. ExecuTorch reads a tensor in memory order rather than by its strides, and a crop built with np.transpose is not contiguous. Random input is, which is why the correlation gate cannot see the difference.

(conversion scripts: executorch-models)

Downloads last month
3
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support