Instructions to use litert-community/RTMPose-Hand-LiteRT with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use litert-community/RTMPose-Hand-LiteRT with LiteRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
| license: apache-2.0 | |
| library_name: LiteRT | |
| pipeline_tag: keypoint-detection | |
| tags: [litert, tflite, on-device, android, gpu, hand-pose, keypoint-detection, rtmpose, mmpose] | |
| base_model: open-mmlab/mmpose | |
| # RTMPose-Hand β LiteRT (on-device 21-keypoint hand pose, fully-GPU) | |
| [RTMPose](https://github.com/open-mmlab/mmpose/tree/main/projects/rtmpose) (mmpose, CSPNeXt + RTMCC/SimCC head) | |
| **hand** pose, converted to **LiteRT** and running **fully on the `CompiledModel` GPU** (ML Drift) on Android. | |
| The **21 standard hand keypoints** (wrist + 4 joints Γ 5 fingers) for a single centered hand. | |
|  | |
| ## On-device (Pixel 8a, Tensor G3 β verified) | |
| | | | | |
| |---|---| | |
| | nodes on GPU | **333 / 333** LITERT_CL (full residency) | | |
| | inference | **~4 ms** (256Γ256) | | |
| | size | 28 MB (fp16) | | |
| | accuracy | device-vs-PyTorch SimCC corr **0.999**, 21/21 keypoints | | |
| ``` | |
| image[1,3,256,256] (ImageNet 0-255) β[GPU: CSPNeXt + RTMCC]β simcc_x[1,21,512], simcc_y[1,21,512] | |
| ``` | |
| ## Minimal usage | |
| **Android (Kotlin, CompiledModel GPU)** | |
| ```kotlin | |
| val model = CompiledModel.create(context.assets, "rtmhand_fp16.tflite", | |
| CompiledModel.Options(Accelerator.GPU), null) | |
| val inputs = model.createInputBuffers() | |
| val outputs = model.createOutputBuffers() | |
| inputs[0].writeFloat(chw) // [1,3,256,256] mmpose mean/std (0-255 RGB), NCHW | |
| model.run(inputs, outputs) | |
| val simccX = outputs[0].readFloat() // [1,21,512] | |
| val simccY = outputs[1].readFloat() // [1,21,512]; keypoint = argmax / 2 | |
| ``` | |
| **Python (desktop verification)** | |
| ```python | |
| MEAN = np.array([123.675, 116.28, 103.53], np.float32) | |
| STD = np.array([58.395, 57.12, 57.375], np.float32) | |
| import numpy as np | |
| from PIL import Image | |
| from ai_edge_litert.interpreter import Interpreter | |
| img = Image.open("hand.jpg").convert("RGB").resize((256, 256)) # centered subject crop | |
| x = ((np.asarray(img, np.float32) - MEAN) / STD).transpose(2, 0, 1)[None] | |
| it = Interpreter(model_path="rtmhand_fp16.tflite"); it.allocate_tensors() | |
| it.set_tensor(it.get_input_details()[0]["index"], x); it.invoke() | |
| od = it.get_output_details() # output 0 = simcc_x, 1 = simcc_y | |
| sx = it.get_tensor(od[0]["index"])[0] # simcc_x [21,512] | |
| sy = it.get_tensor(od[1]["index"])[0] # simcc_y [21,512] | |
| kx, ky = sx.argmax(-1) / 2.0, sy.argmax(-1) / 2.0 # 21 keypoints, px in 256x256 | |
| for i, (a, b) in enumerate(zip(kx, ky)): | |
| print(f"kp{i}: ({a:.1f}, {b:.1f})") | |
| ``` | |
| ## How it converts (litert-torch) | |
| Identical RTMPose-family recipe (both numerically exact, no PixelShuffle since there's no neck): | |
| 1. **`ScaleNorm` (RMS) β SafeRMSNorm** β fp16-overflow all-zero-head fix (scale x down by S=64 before squaring). | |
| 2. **GAU `act@act` BMM β broadcast-multiply + reduce-sum**. | |
| Result: banned ops NONE, all tensors β€4D, tflite-vs-torch corr **1.0**, device-vs-torch corr **0.999**. | |
| ## Preprocessing | |
| Center-crop to square, resize to 256Γ256, ImageNet 0-255 normalize, NCHW. Top-down β one centered hand. | |
| SimCC argmax (Γ· split=2) β pixel. | |
| ## License | |
| [Apache-2.0](https://github.com/open-mmlab/mmpose/blob/main/LICENSE). Upstream: | |
| [open-mmlab/mmpose](https://github.com/open-mmlab/mmpose) RTMPose-Hand. | |