A fork of SoccerMaster, refactored into a package, for easy use in notebooks.
This repository is a fork. It is not the official release. Upstream is the official implementation of SoccerMaster: A Vision Foundation Model for Soccer Understanding (CVPR 2026 Oral) by Haolin Yang, Jiayuan Rao, Haoning Wu and Weidi Xie.
The model, the data pipeline and the game-state reconstruction logic are the upstream authors' work. This fork only changes how it is packaged and driven — see About this fork below.
SoccerMaster is a unified soccer-specific vision foundation model that leverages diverse soccer content, including images and videos, to support a wide range of soccer understanding tasks, such as commentary generation, detection, tracking, classification, etc.
SoccerMaster Architecture. (a) The architecture of SoccerMaster, which encodes both soccer videos and images through spatial and temporal attention modules to generate semantically rich representations. (b) The pretraining tasks and downstream adaptations of SoccerMaster across both spatial perception and semantic understanding tasks.
The upstream release ships as four separate projects glued together under codes/
(SoccerMaster, sn-gamestate, tracklab, sam2), each with its own
poetry/setup.py, its own import root, and a cd-and-ln -s quick start that
does not survive a pip install. That is fine for reproducing a paper on one
workstation; it is painful the moment you want to open a notebook and just use
the model.
This fork makes it one installable distribution you can pip install straight
from GitHub — on Colab or Kaggle — and then drive from Python:
!pip install "soccermaster[pipeline] @ git+https://github.com/SurrealisticRabbit/SoccerMaster.git@main"
import soccermaster as sm
sm.prepare("siglip") # fetch weights, no manual layout
sm.prepare("soccermaster")
model = sm.load_model() # -> MultiTaskingModel
outputs = sm.predict(model, "frames/SNGS-10001", task="detection")
sm.run_pipeline("data/SoccerNetGS", steps=(1, 3)) # game-state pipelineWhat changed:
| Upstream | This fork | |
|---|---|---|
| Packaging | four separate installable projects | one distribution, pip install from GitHub |
| Import root | tracklab, sn_gamestate, sam2 |
soccermaster.*, single namespace |
| Weight setup | manual hf download per model + ln -s |
soccermaster prepare into a known weights/ tree |
| Entry point | cd into a directory and run a script |
soccermaster CLI + soccermaster.api |
| Notebook use | not supported | load_model / predict / run_pipeline |
The model, data pipeline and game-state logic are untouched: same module order,
same head names, same pickle schema, same loss and schedule numbers. Nothing has
been retrained or swapped, and no vendored code was relicensed — vendored folders
are named after their upstream, with original headers intact (see
PROVENANCE.md and THIRD_PARTY_NOTICES.md).
Verified on a Colab T4 (Python 3.13, torch 2.11+cu130, transformers 4.51.3): install
from GitHub, load_model() (967.8 M parameters, five heads, onto the GPU) and
predict(..., task="detection") all run. The 3-step pipeline has not been run
end to end yet.
Scope notes: SAM 2 stays an optional extra and step 2 needs a CUDA build. The model
weights are covered by soccermaster prepare; the reid and calibration weights
are fetched by the pipeline itself from Zenodo on first use, so they need no manual
step. The rest of this README documents the refactored package; upstream commands
survive below where they are still valid, with their paths updated.
Package folders are named after their upstream so you can tell at a glance what came from where:
pyproject.toml # one distribution: "soccermaster"
src/soccermaster/
├── api.py # notebook-friendly API (load_model / predict / run_pipeline)
├── cli.py # `soccermaster` console script
├── downloads.py # weight fetching (Hugging Face / Google Drive)
├── paths.py # data / weights / outputs locations
├── pipeline.py # 3-step game-state pipeline runner
├── model/ # SoccerMaster foundation model — this paper
├── tracklab/ # TrackLab tracking framework — vendored (MIT)
├── soccernet_gamestate/ # SoccerNet game-state reconstruction — vendored
│ └── plugins/calibration/ # TVCalib, PnLCalib, NBJW, sn_calibration_baseline
├── sam2_refine/ # SAM 2 mask refinement — vendored glue
└── resources/ # weight manifest and small assets
third_party/sam2/ # vendored SAM 2 library (optional, not installed by default)
docs/ # TrackLab, SoccerNet-GSR and calibration documentation
model/, api.py, cli.py, pipeline.py and downloads.py are ours. Everything
under tracklab/, soccernet_gamestate/, sam2_refine/, third_party/ and the
vendored bits of docs/ came from other projects — see
PROVENANCE.md for the full attribution, including which
pretrained weights come from Google, SoccerNet, Alibaba and Meta.
Python 3.10+ is required. PyTorch must be installed first with the CUDA wheel index so that pip does not pull a CPU-only build over an existing CUDA install:
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install torch==2.4.1 torchvision==0.19.1 torchaudio==2.4.1 --index-url https://download.pytorch.org/whl/cu121
pip install -e .Optional extras:
pip install -e ".[pipeline]" # everything the 3-step pipeline imports (steps 1 and 3)
pip install -e ".[sam2]" # SAM 2 runtime deps, needed for pipeline step 2
pip install -e ".[train]" # flash-attn, only needed to train
pip install -e ".[dev]" # ruff + pytestThe base install is deliberately lean: it covers import soccermaster,
load_model and predict. Running the game-state pipeline needs the pipeline
extra, whose dependencies are only reachable from the pipeline modules:
soccermaster pipeline --dataset ./data/SoccerNetGS --steps 1,3 --device 0The SAM 2 library itself is vendored at third_party/sam2 and is not part of the
installed wheel. Install it as well if you want to run step 2:
pip install -e third_party/sam2Install straight from GitHub (@main, or a tag once you cut one):
!pip install "soccermaster[pipeline] @ git+https://github.com/SurrealisticRabbit/SoccerMaster.git@main"Notes for hosted notebooks:
import soccermasterneeds no third-party packages at all. The package re-exports its API lazily, so the import succeeds before any dependency is installed — useful to confirm the install landed.- torch is not pinned above. The project declares
torch>=2.4with no ceiling, so the runtime's own CUDA-matched torch is left alone. Setting an upper bound here made the package uninstallable (see the note below). - transformers is capped below 4.52. 5.x flattened
SiglipVisionModeland 4.57.6 has a bug infrom_pretrained, so the cap is load-bearing. If you downgrade transformers in place on Colab, uninstall first — otherwise files from the newer release are left behind and break imports:pip uninstall -y transformers.
examples/example.ipynb runs this whole path on a Colab T4 and records the versions
it was verified against.
soccermaster prepare reads src/soccermaster/resources/weights_manifest.yaml:
soccermaster prepare --list # show every entry and its destination
soccermaster prepare --dry-run siglip # show what would be fetched
soccermaster prepare siglip soccermaster yolo # fetch specific entries
soccermaster prepare # fetch every automatic entry| entry | source | notes |
|---|---|---|
siglip |
Hugging Face | SigLIP2 backbone used by the encoder |
soccermaster |
Hugging Face | SoccerMaster checkpoints |
yolo |
Hugging Face | person detector for step 1 |
qwen7b / qwen72b |
Hugging Face | jersey number + role recognition |
sam2 |
Hugging Face | SAM 2 video predictor checkpoint |
legibility |
Google Drive | ResNet34 legibility classifier |
reid, calibration |
runtime | the pipeline fetches these from Zenodo on first use; prepare skips them |
For step 1 the checkpoint that is easy to miss is the YOLO detector: the configs ask
for weights/yolo/yolo_v8x6_person_lr_default_best.pt, and the manifest fetches
yolo_v8x6_finetuned.pt from Hugging Face and renames it to that name.
reid and calibration are marked runtime: the ReID module
(prtreid_api.download_models) and the calibration module (nbjw_calib) download
their own weights from Zenodo on first use, md5-verified, skipping the download when
the file is already present. soccermaster prepare therefore does nothing for them.
| purpose | default location | override |
|---|---|---|
| weights | ./weights |
SOCCERMASTER_HOME |
| datasets | ./data |
SOCCERMASTER_HOME |
| outputs | ./outputs |
SOCCERMASTER_HOME |
In an editable install these default to the repository root; for a regular install
they default to ~/.cache/soccermaster. Set SOCCERMASTER_HOME=/some/dir to put
all three somewhere else.
import soccermaster as sm
sm.prepare("siglip")
sm.prepare("soccermaster")
model = sm.load_model() # -> MultiTaskingModel
outputs = sm.predict(model, "frames/SNGS-10001", task="detection")
print(outputs.keys()) # e.g. {'SoccerNetGSR_Detection': {...}}task is one of detection, lines, keypoints, caption, classification or
all. Outputs are the raw head outputs (no NMS / bbox rescaling), matching the
original inference_demo.py. For a random-input smoke test of the weights:
soccermaster foundation-demoThe data pipeline follows the SoccerNet Game State Recognition (GSR) format. Organise your input frames as:
data/SoccerNetGS/
├── sequences_info.json
└── sn500/
├── SNGS-10001/
│ └── img1/
│ ├── 000001.jpg
│ └── ... (750 frames)
└── SNGS-10002/
└── img1/
sequences_info.json registers all sequences:
{
"sn500": [
{ "id": 0, "name": "SNGS-10001", "n_frames": 750 },
{ "id": 1, "name": "SNGS-10002", "n_frames": 722 }
]
}Run the three steps with one command (paths and state files are injected for you):
# all steps, specific sequences
soccermaster pipeline --dataset ./data/SoccerNetGS --videos 10001,10002 --device 0
# steps 1 and 3 only (no SAM 2 refinement)
soccermaster pipeline --dataset ./data/SoccerNetGS --steps 1,3 --out ./outputs/pipeline| step | what it does | config |
|---|---|---|
| 1 | person detection + tracking | gsr_step_1_example |
| 2 | SAM 2 mask refinement (needs the sam2 extra) |
soccermaster.sam2_refine.inference |
| 3 | calibration, jersey number, role, team assignment | gsr_step_3_example_accelerate |
Outputs land in outputs/pipeline/step1/sn-gamestate.pklz,
outputs/pipeline/step2/refined_sn-gamestate.pklz and
outputs/pipeline/step3/sn-gamestate.pklz.
Model selection for step 3: the accelerated config (
gsr_step_3_example_accelerate, used by default) runs jersey-number and role recognition in a single Qwen2.5-VL-7B module. For higher accuracy at higher cost, usegsr_step_3_examplewith Qwen2.5-VL-72B for jersey numbers.
Platform notes: steps 1 and 3 and model training run as plain Python and work on Windows and Linux. Step 2 requires a CUDA build plus the
sam2extra.
Each step is still a normal Hydra entry point, so the original commands work:
python -m soccermaster.tracklab.main -cn gsr_step_1_example
python -m soccermaster.tracklab.main -cn gsr_step_3_example_accelerate
python -m soccermaster.sam2_refine.inference --help
python -m soccermaster.model.data.extract_frames --helpWhen invoking TrackLab directly, remember it uses the current working directory:
data_dir, model_dir and dataset.dataset_path are ${project_dir}/... by
default, so pass data_dir=..., model_dir=... and dataset.dataset_path=...
overrides — that is exactly what soccermaster pipeline does.
soccermaster train --config-path src/soccermaster/model/configs/pretrain.yaml --data-root ./data
soccermaster eval --config src/soccermaster/model/configs/pretrain.yaml --checkpoint ./weights/SoccerMasterArguments are forwarded unchanged to the original train.py / eval.py, so all
their flags are available (--resume-training, --outputs-dir, --exp-name, ...).
We release the Soccer Factory dataset containing 7,000 videos with per-frame annotations (bounding boxes, roles, jersey numbers, and camera parameters). The data is distributed as H.264-encoded videos and JSON annotations.
Download the following files from Dropbox:
| File | Contents | Size |
|---|---|---|
soccer_factory_annotations.tar.gz |
Per-frame annotations (JSON) | 2.4 GB |
soccer_factory_videos_part1.tar |
1,000 H.264 videos | 18.8 GB |
soccer_factory_videos_part2.tar |
1,000 H.264 videos | 18.0 GB |
soccer_factory_videos_part3.tar |
1,000 H.264 videos | 19.3 GB |
soccer_factory_videos_part4.tar |
1,000 H.264 videos | 19.5 GB |
soccer_factory_videos_part5.tar |
1,000 H.264 videos | 18.1 GB |
soccer_factory_videos_part6.tar |
1,000 H.264 videos | 16.5 GB |
soccer_factory_videos_part7.tar |
1,000 H.264 videos | 16.0 GB |
SHA256SUMS |
SHA-256 checksums for the archives | < 1 KB |
Each video archive contains 1,000 sequences. The parts preserve the order of the released ID list, so the IDs in an individual part are not necessarily a contiguous numeric range. Use the filenames within an archive rather than inferring an ID range from its part number. Verify downloaded files against SHA256SUMS before extraction.
mkdir -p data/SoccerNetGS/extracted_info
tar xzf soccer_factory_annotations.tar.gz
mv annotations/* data/SoccerNetGS/extracted_info/The video tar files contain H.264-encoded .mp4 files. Use the provided script to decode them back into image sequences:
# Option A: decode directly from tar files (recommended, no intermediate extraction)
python -m soccermaster.model.data.extract_frames \
--tar_files soccer_factory_videos_part*.tar \
--output_dir data/SoccerNetGS/sn500 \
--quality 95
# Option B: extract tar files first, then decode
tar xf soccer_factory_videos_part1.tar
python -m soccermaster.model.data.extract_frames \
--video_dir ./videos \
--output_dir data/SoccerNetGS/sn500 \
--quality 95--output_dir defaults to <data_dir>/SoccerNetGS/sn500. Dependencies: ffmpeg
must be installed (apt install ffmpeg or brew install ffmpeg). The script
supports resumption — re-running skips already-extracted sequences.
data/SoccerNetGS/
├── extracted_info/ # Annotations (JSON)
│ ├── SNGS-10001.json
│ └── ... (7000 files)
└── sn500/ # Image sequences
├── SNGS-10001/
│ └── img1/
│ ├── 000001.jpg
│ └── ... (up to ~750 frames per sequence)
└── ... (7000 directories)
In src/soccermaster/model/configs/default.yaml (or on the command line):
USE_SOCCER_FACTORY_DATA: True
SOCCER_FACTORY_DATA_DIR: ./data/SoccerNetGS/extracted_info
SOCCER_FACTORY_DATA_IMAGE_DIR: ./data/SoccerNetGS/sn500
USE_SOCCER_FACTORY_DATA_AMOUNT: 7000 # -1 to use allEach JSON file (e.g., SNGS-10001.json) contains per-frame annotations keyed by frame ID (1-indexed string):
{
"1": {
"people": [
{
"id": 1,
"bbox_ltwh": [x, y, w, h],
"role": "player",
"legibility_score": 0.95,
"jersey_number": 7.0
}
],
"valid_cam_params": true,
"K": [[...], [...], [...]],
"R": [[...], [...], [...]]
}
}Fields:
people[].bbox_ltwh: Bounding box in (left, top, width, height) format, pixel coordinates for 1920x1080 images.people[].role: One of"player","goalkeeper","referee","ball","other".people[].legibility_score: Confidence of jersey number visibility (0.0 to 1.0).people[].jersey_number: Jersey number (float or null).valid_cam_params: Whether camera calibration is available for this frame.K: 3x3 camera intrinsic matrix.R: 3x3 rotation matrix.
The version comes from the git tag via setuptools-scm — there is no number to edit
by hand. Tags are normalised to PEP 440:
| tag | package version |
|---|---|
v1.0.1-alpha |
1.0.1a0 |
v0.2.0-beta1 |
0.2.0b1 |
v2.0.0-rc1 |
2.0.0rc1 |
v1.0.0 |
1.0.0 |
A commit after a tag reports <version>.post1.devN+g<hash> rather than claiming a
future release, so a wheel built from main is traceable to a commit and clearly not
the release itself.
pip install -e ".[dev]"
pytestThe suite is a regression suite, not exhaustive coverage: it targets the failures this
project actually hit — the package importing lazily, the hydra_plugins package
existing, both pipeline configs composing with every _target_ resolvable, paths
retargeting under weights_dir, the manifest being complete, and the exporter
round-tripping. It runs on CPU with no weights and no GPU; tests needing an optional
dependency skip instead of failing, so the same suite works in a light and a full
environment.
soccermaster doctor --steps 1,3 is the runtime equivalent: it checks the same things
against your actual machine and weights before you start a long run.
Push a tag; the rest is automatic:
git tag v1.0.1-alpha
git push origin v1.0.1-alpha.github/workflows/release.yml then runs the tests, builds the sdist and wheel,
asserts that the artefact carries the tag's version and that the wheel contains the
Hydra configs and the search-path plugin, and publishes a GitHub release. A tag
containing a hyphen is marked as a pre-release.
ci.yml runs the same tests on pushes to main and on pull requests, across Python
3.10, 3.12 and 3.13.
This repository vendors code from TrackLab (MIT), SAM 2 (Apache-2.0), the SoccerNet
Game State Recognition and camera-calibration kits, TVCalib and others. See
THIRD_PARTY_NOTICES.md for the full list and the
preserved license texts under third_party/licenses/.
If you find our work useful, please cite:
@inproceedings{yang2025soccermaster,
title={SoccerMaster: A Vision Foundation Model for Soccer Understanding},
author={Yang, Haolin and Rao, Jiayuan and Wu, Haoning and Xie, Weidi},
journal={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)},
year={2026}
}
