Spaces:
Running on Zero
Running on Zero
Download lib/exmr/model/refiners.py from hugging-apps/exmr-motion-refinement: direct link, hf CLI and curl.
- Browser
- Download file 4.04 kB
-
https://huggingface.co/spaces/hugging-apps/exmr-motion-refinement/resolve/main/lib/exmr/model/refiners.py
- Command line
-
hf download hf://spaces/hugging-apps/exmr-motion-refinement/lib/exmr/model/refiners.py
-
curl -L -o refiners.py https://huggingface.co/spaces/hugging-apps/exmr-motion-refinement/resolve/main/lib/exmr/model/refiners.py
4.04 kB
| """FootMR and HandMR: temporal refiners that predict residual extremity rotations.""" | |
| import torch.nn as nn | |
| from exmr.model.body_net import KeypointEmbedder | |
| from exmr.model.layers import Mlp, RoPEEncoder, condition_embedder, feature_embedder | |
| class FootRefiner(nn.Module): | |
| """FootMR: refines both global ankle rotations from the 2D ankle and foot keypoints. | |
| Conditioned on the initial global knee and ankle rotations, it predicts the refined global | |
| ankle rotations as a residual on the initial ones (6D, left then right). | |
| """ | |
| def __init__( | |
| self, | |
| num_2d_joints=8, # 2 x (ankle, big toe, small toe, heel) | |
| num_rot_condition=4, # global knee and ankle rotations, left and right | |
| output_dim=2 * 6, # global ankle rotations, left and right | |
| latent_dim=256, | |
| num_layers=6, | |
| num_heads=4, | |
| mlp_ratio=2.0, | |
| max_len=120, | |
| dropout=0.1, | |
| ): | |
| super().__init__() | |
| self.output_dim = output_dim | |
| self.kp2d_embedder = KeypointEmbedder(num_2d_joints, latent_dim, dropout) | |
| self.cliffcam_embedder = condition_embedder(3, latent_dim, dropout) | |
| self.rot_6d_embedder = condition_embedder(6 * num_rot_condition, latent_dim, dropout) | |
| self.encoder = RoPEEncoder(latent_dim, num_layers, num_heads, mlp_ratio, dropout, max_len) | |
| self.final_layer = Mlp(latent_dim, out_features=output_dim) | |
| def forward(self, length, kp2d, cliffcam, rotations_6d, frame_valid=None): | |
| """ | |
| Args: | |
| length: (B,) | |
| kp2d: (B, L, 8, 3) box-normalized foot keypoints | |
| cliffcam: (B, L, 3) | |
| rotations_6d: (B, L, 24) global [knees, ankles] 6D rotations | |
| Returns: | |
| (B, L, 12) refined global ankle rotations (6D) | |
| """ | |
| x = self.kp2d_embedder(kp2d) | |
| x = x + self.cliffcam_embedder(cliffcam) | |
| x = x + self.rot_6d_embedder(rotations_6d) | |
| x, _ = self.encoder(x, length, frame_valid) | |
| return self.final_layer(x) + rotations_6d[:, :, -self.output_dim :] | |
| class HandRefiner(nn.Module): | |
| """HandMR: refines elbows, wrists and fingers from HaMeR hand features. | |
| Conditioned on the initial global elbow and wrist rotations and the parent-relative finger | |
| rotations, it predicts refined ones as a residual (6D): global elbows (2), global wrists (2), | |
| then the 2 x 15 finger joints. | |
| """ | |
| def __init__( | |
| self, | |
| hand_feat_dim=1024, # HaMeR token, per hand | |
| num_rot_condition=2 * (2 + 15), # elbow, wrist and fingers, left and right | |
| output_dim=2 * 17 * 6, | |
| latent_dim=512, | |
| num_layers=6, | |
| num_heads=4, | |
| mlp_ratio=2.0, | |
| max_len=120, | |
| dropout=0.1, | |
| ): | |
| super().__init__() | |
| self.output_dim = output_dim | |
| # each hand gets half of the channels | |
| self.hand_feat_embedder = feature_embedder(hand_feat_dim, latent_dim // 2) | |
| self.cliffcam_embedder = condition_embedder(3, latent_dim, dropout) | |
| self.rot_6d_embedder = condition_embedder(6 * num_rot_condition, latent_dim, dropout) | |
| self.encoder = RoPEEncoder(latent_dim, num_layers, num_heads, mlp_ratio, dropout, max_len) | |
| self.final_layer = Mlp(latent_dim, out_features=output_dim) | |
| def forward(self, length, hand_feat, cliffcam, rotations_6d, frame_valid=None): | |
| """ | |
| Args: | |
| length: (B,) | |
| hand_feat: (B, L, 2, 1024) HaMeR image features (left, right) | |
| cliffcam: (B, L, 3) | |
| rotations_6d: (B, L, 204) [global elbows, global wrists, fingers] 6D rotations | |
| Returns: | |
| (B, L, 204) refined rotations in the same layout (6D) | |
| """ | |
| B, L = rotations_6d.shape[:2] | |
| x = self.hand_feat_embedder(hand_feat).reshape(B, L, -1) | |
| x = x + self.cliffcam_embedder(cliffcam) | |
| x = x + self.rot_6d_embedder(rotations_6d) | |
| x, _ = self.encoder(x, length, frame_valid) | |
| return self.final_layer(x) + rotations_6d[:, :, -self.output_dim :] | |