Downloads · 30 days
0
Mercity/figure-skating-transformer
figure-skating-transformer is a machine learning model from Mercity. Use it for the machine learning task on the model card, and read the license before you ship it in a product. It is set up for pytorch. The card lists the license as other.
A Conv1D backbone + Transformer-encoder baseline for classifying figure-skating actions (jumps, spins, sequences) from pose-skeleton time series. Sinusoidal positional encoding + a real 3-layer nn.TransformerEncoder (…
Downloads · 30 days
0
Access
Public
Updated Jul 21, 2026
Repo size
60.2 MB
Likes
0
Public
Click a slice to open those files.
.pt60.2 MB · 100%
From the Hugging Face model README
A Conv1D backbone + Transformer-encoder baseline for classifying figure-skating actions (jumps,
spins, sequences) from pose-skeleton time series. Sinusoidal positional encoding + a real
3-layer nn.TransformerEncoder (self-attn + FFN per layer) on top of the same Conv1D residual
backbone used across this model family.
This repo holds two checkpoints trained on the same architecture and data split, differing only in label granularity:
| file | label space | classes |
|---|---|---|
model_transformer_fine.pt | fine-grained | 28 (jump rotation-count preserved, e.g. 3Lutz, 2Axel) |
model_transformer_coarse.pt | coarse | 11 (jump rotation-count collapsed, e.g. Lutz, Axel) |
Not transformers-compatible in the HF sense — this is a plain PyTorch nn.Module +
state_dict checkpoint (custom architecture, not a Hub AutoModel). Model source code
(SkatingActionClassifier in the project's model_transformers.py, which depends on
model.py) is not included in this repo — you'll need the project source to reconstruct
the class before loading the state dict.
from huggingface_hub import hf_hub_download
import torch
repo_id = "Mercity/figure-skating-transformer"
ckpt_path = hf_hub_download(repo_id, "model_transformer_fine.pt")
ckpt = torch.load(ckpt_path, map_location="cpu", weights_only=False)
# reconstruct with the project's SkatingActionClassifier (model_transformers.py):
# model = SkatingActionClassifier(ckpt["in_features"], ckpt["num_classes"])
# model.load_state_dict(ckpt["state_dict"])
# model.eval()
# ckpt also carries the standardization stats used at train time and the taxonomy:
mu, sd = ckpt["feature_mean"], ckpt["feature_std"] # normalize inputs with (x - mu) / sd
taxonomy = ckpt["taxonomy"] # {0: "3Toeloop", 1: "3Loop", ...}
Swap model_transformer_fine.pt for model_transformer_coarse.pt to load the 11-class variant.
| Backbone | Conv1D stem(128) → ConvBlock(192,k3) → ConvBlock(256,k3) → ConvBlock(384,k5) |
| Temporal block | Sinusoidal positional encoding + nn.TransformerEncoder, 3 layers, d_model=384, nhead=8, dim_feedforward=1536 (4×d_model), dropout=0.1, GELU, post-norm |
| Head | Dense(384→1024,p0.5) → Dense(1024→512,p0.4) → Dense(512→256,p0.3) → LayerNorm(256) → Linear(256→num_classes) |
| Optimizer | Adam, lr=5e-4, weight_decay=1e-4 |
| Batch size | 64 |
| Grad clip | 1.0 |
| Class weight cap | 5.0 |
| Early stop | patience 20 on val macro-F1, 100-epoch cap |
| Seed | 42 |
| Params | 7.31M (both) |
Trained on skeleton-extracted figure-skating clips (YOLO11n-pose, COCO-17 joints, imgsz=384) from an internal Mercity dataset. Stratified train/val/test split, seed 42. Not included in this repo (private internal dataset).
Early-stopped epoch 42 (best val macro-F1 0.572)
Overall: accuracy 0.8348 · precision (macro/weighted) 0.4511 / 0.8364 · recall 0.5129 / 0.8348 · F1 0.4642 / 0.8287
| class | precision | recall | f1 | support |
|---|---|---|---|---|
| 3Toeloop | 0.514 | 0.500 | 0.507 | 38 |
| 3Loop | 0.607 | 0.810 | 0.694 | 21 |
| 2Axel | 0.919 | 0.791 | 0.850 | 43 |
| CamelSpin | 0.991 | 0.912 | 0.950 | 125 |
| SitSpin | 0.969 | 0.955 | 0.962 | 132 |
| UprightSpin | 0.934 | 0.917 | 0.925 | 108 |
| 2Salchow | 0.286 | 0.400 | 0.333 | 5 |
| 2Toeloop | 0.658 | 0.781 | 0.714 | 32 |
| 3Salchow | 0.381 | 0.381 | 0.381 | 21 |
| 3Axel | 0.867 | 0.867 | 0.867 | 15 |
| 3Flip | 0.538 | 0.389 | 0.452 | 36 |
| 3Lutz | 0.667 | 0.244 | 0.357 | 41 |
| NoBasic | 0.757 | 0.903 | 0.824 | 31 |
| 2Lutz | 0.214 | 0.429 | 0.286 | 7 |
| 4Salchow | 0.200 | 0.333 | 0.250 | 3 |
| 4Flip | 0.000 | 0.000 | 0.000 | 1 |
| 4Toeloop | 0.200 | 0.167 | 0.182 | 6 |
| 4Lutz | 0.000 | 0.000 | 0.000 | 1 |
| 4Loop | 0.000 | 0.000 | 0.000 | 1 |
| 2Flip | 0.333 | 0.500 | 0.400 | 8 |
| 2Loop | 0.500 | 0.750 | 0.600 | 8 |
| 1Axel | 0.333 | 0.333 | 0.333 | 3 |
| 1Loop | 0.500 | 1.000 | 0.667 | 1 |
| 1Salchow | 0.000 | 0.000 | 0.000 | 1 |
| 1Toeloop | 0.333 | 1.000 | 0.500 | 1 |
| 1Flip | 0.000 | 0.000 | 0.000 | 2 |
| 1Lutz | 0.000 | 0.000 | 0.000 | 1 |
| Sequence | 0.930 | 1.000 | 0.964 | 307 |
| macro avg | 0.451 | 0.513 | 0.464 | 999 |
| weighted avg | 0.836 | 0.835 | 0.829 | 999 |
Early-stopped epoch 61 (best val macro-F1 0.860)
Overall: accuracy 0.8989 · precision (macro/weighted) 0.8390 / 0.8989 · recall 0.8158 / 0.8989 · F1 0.8233 / 0.8970
| class | precision | recall | f1 | support |
|---|---|---|---|---|
| Axel | 0.879 | 0.951 | 0.913 | 61 |
| Toeloop | 0.728 | 0.870 | 0.793 | 77 |
| Salchow | 0.737 | 0.467 | 0.571 | 30 |
| Loop | 0.793 | 0.742 | 0.767 | 31 |
| Flip | 0.714 | 0.638 | 0.674 | 47 |
| Lutz | 0.750 | 0.720 | 0.735 | 50 |
| CamelSpin | 0.976 | 0.976 | 0.976 | 125 |
| SitSpin | 0.976 | 0.917 | 0.945 | 132 |
| UprightSpin | 0.871 | 0.935 | 0.902 | 108 |
| Sequence | 0.977 | 0.984 | 0.981 | 307 |
| NoBasic | 0.828 | 0.774 | 0.800 | 31 |
| macro avg | 0.839 | 0.816 | 0.823 | 999 |
| weighted avg | 0.899 | 0.899 | 0.897 | 999 |
Axel (95.1%) and Toeloop (87.0%) recall of all architectures tested, but by far the
worst Salchow recall (46.7%) — heavily biased toward calling Salchow "Toeloop"
(11/30 test samples, the single worst confusion pair measured across every model tried).Flip ↔ Lutz confusion present but less severe than in other architectures.4Flip, 4Lutz, 4Loop, 1Salchow, 1Toeloop, 1Flip, 1Lutz) — a data scarcity issue,
not an architecture weakness.Internal/proprietary — not licensed for external use. Contact the Mercity team for access terms.