OpenSportsLib is a modular Python library for sports video understanding.
It provides a unified framework to train, evaluate, and run inference for key temporal understanding tasks in sports video, including:
- Action classification
- Action localization / spotting
- Visual Question Answering (VQA)
- Action retrieval
- Action description / captioning
OpenSportsLib is designed for researchers, ML engineers, and sports analytics teams who want reproducible and extensible workflows for sports video AI.
- Unified workflow for training and inference
- Modular design for adding new tasks, datasets, and models
- Config driven experiments for reproducibility
- Optional SpoTTA test-time adaptation for E2ESpot inference
- Support for multiple modalities and sports workflows
- Research friendly while still usable in applied settings
- Documentation: https://opensportslab.github.io/opensportslib/
- OSL JSON format: https://opensportslab.github.io/opensportslib/data/osl-json-format/
- PyPI: https://pypi.org/project/opensportslib/
- Issues: https://github.com/OpenSportsLab/opensportslib/issues
Requires Python 3.12+.
Supports CUDA 12.6 / 12.8 / 13.0 (with CPU fallback).
PyTorch Geometric is supported up to PyTorch 2.10.*.
conda create -n osl python=3.12 pip -y
conda activate oslpip install opensportslibpip install --pre opensportslibpip install -e .# Install PyTorch (CPU/GPU auto-detected)
opensportslib setup
# Optional: install PyTorch Geometric support
opensportslib setup --pyg
# Optional: install for DALI support
opensportslib setup --dali
# Optional: install the X-VARS-compatible VQA dependency profile
opensportslib setup --vqa_xvars
# Optional: install the Qwen-compatible VQA dependency profile
opensportslib setup --vqa_qwenNote:
Run opensportslib setup to automatically configure dependencies.
If issues occur, manually install compatible versions of torch, torchvision, and related libraries according to your CUDA version or system compatibility.
For VQA, use exactly one backend-specific dependency profile:
--vqa_xvarsinstalls the X-VARS-compatible Hugging Face stack fromXVARS_DEPENDENCY_PINS--vqa_qweninstalls the Qwen-compatible Hugging Face stack fromQWEN_DEPENDENCY_PINS
The vqa_qwen config supports Qwen/Qwen2.5-7B-Instruct and Qwen/Qwen3.5-9B-Base.
OpenSportsLib uses external annotation files, datasets, and pretrained checkpoints.
Public assets are hosted under the OpenSportsLab Hugging Face organization:
https://huggingface.co/OpenSportsLab
Use it as the main entry point to find:
- datasets
- annotation files
- extracted features
- pretrained models and checkpoints
See the Model Zoo for available pretrained models, reported scores, datasets, and loading snippets.
OpenSportsLib annotation files use the OSL JSON v2.0 format. A dataset JSON
contains top-level metadata, a shared labels schema, and a data array where
each sample points to one or more inputs.
Minimal classification sample:
{
"labels": {
"action": {
"type": "single_label",
"labels": ["pass", "shot"]
}
},
"data": [
{
"id": "clip_0001",
"inputs": [
{
"type": "video",
"path": "clips/clip_0001.mp4",
"fps": 25.0
}
],
"labels": {
"action": {
"label": "shot"
}
}
}
]
}Minimal localization sample:
{
"labels": {
"action": {
"type": "single_label",
"labels": ["pass", "shot"]
}
},
"data": [
{
"id": "game_0001",
"inputs": [
{
"type": "video",
"path": "games/game_0001.mp4",
"fps": 25.0
}
],
"events": [
{
"head": "action",
"label": "pass",
"position_ms": 1240
}
]
}
]
}Relative paths in inputs[].path are resolved from the split media root in the
YAML config, for example DATA.common.splits.train.source_path. Localization
records may also declare half-open physical-video ranges in
metadata.intervals; the OpenCV loader treats them as ordered logical videos
and evaluates only segments marked verified. See the full
OSL JSON format guide for field definitions,
multi-modal examples, prediction payloads, and conversion notes.
import opensportslib
print("OpenSportsLib imported successfully")from opensportslib.apis import ClassificationModel
my_model = ClassificationModel(
config="/path/to/classification.yaml",
weights=None, # optional: path or Hugging Face model ID
)
my_model.train(
train_set="/path/to/train_annotations.json",
valid_set="/path/to/valid_annotations.json",
)from opensportslib.apis import ClassificationModel
my_model = ClassificationModel(
config="/path/to/classification.yaml",
weights=None, # optional: path or Hugging Face model ID
)
predictions = my_model.infer(
test_set="/path/to/test_annotations.json",
)
saved_predictions = my_model.save_predictions(
output_path="/path/to/predictions.json",
predictions=predictions,
)
metrics = my_model.evaluate(
test_set="/path/to/test_annotations.json",
)
metrics_from_file = my_model.evaluate(
test_set="/path/to/test_annotations.json",
predictions=saved_predictions,
)
print(metrics)from opensportslib.apis import LocalizationModel
my_model = LocalizationModel(
config="/path/to/localization_video_dali.yaml",
weights=None, # optional: path or Hugging Face model ID
)
predictions = my_model.infer(
test_set="/path/to/test_annotations.json",
)
saved_predictions = my_model.save_predictions(
output_path="/path/to/predictions.json",
predictions=predictions,
)
metrics = my_model.evaluate(
test_set="/path/to/test_annotations.json",
)
metrics_from_file = my_model.evaluate(
test_set="/path/to/test_annotations.json",
predictions=saved_predictions,
)from opensportslib.apis import VQAModel
my_model = VQAModel(
config="opensportslib/configs/vqa/qwen.yaml",
weights=None, # optional: path or Hugging Face model ID
)
predictions = my_model.infer(
test_set="/path/to/test_annotations.json",
)
# Headless single-video VQA uses the same prediction payload shape.
single_prediction = my_model.infer(
video_path="/path/to/video.mp4",
question="What card would you give? Why?",
)Use opensportslib/configs/vqa/xvars.yaml with opensportslib setup --vqa_xvars
for the X-VARS backend. OpenSportsLib supports three VQA options:
opensportslib/configs/vqa/xvars.yamlOriginal X-VARS / Video-ChatGPT path.- CLIP features + Qwen
Use
opensportslib/configs/vqa/qwen.yamlfor inference andopensportslib/configs/vqa/qwen_lora.yamlfor LoRA training. opensportslib/configs/vqa/qwen3_vl_native.yamlFull end-to-end native QwenVL path. This is the single canonical QwenVL config; changeMODEL.components.llm_decoder.params.repo_idto switch model IDs.
Use opensportslib setup --vqa_qwen for both the CLIP+Qwen and native QwenVL
paths. The CLIP+Qwen configs support Qwen/Qwen2.5-7B-Instruct and
Qwen/Qwen3.5-9B-Base. The native QwenVL config defaults to
Qwen/Qwen3-VL-8B-Instruct and supports:
Qwen/Qwen3-VL-8B-InstructQwen/Qwen2.5-VL-7B-Instruct
For X-VARS, feature_source: indexed_or_raw_clip prefers indexed CLIP features
when available and falls back to extracting CLIP features from raw video during
infer(). Pre-extracted features remain the preferred path for parity, speed,
and reproducibility. See docs/tools/vqa.md for the full
VQA setup workflow.
OpenSportsLib provides APIs and scripts for downloading and uploading OSL datasets with Hugging Face.
from opensportslib.tools import (
download_dataset_split_from_hf,
upload_dataset_inputs_from_json_to_hf,
upload_dataset_as_parquet_to_hf,
)python tools/download/download_osl_hf.py --repo-id <org/repo> --revision main --split test --format parquet --output-dir downloaded_data
python tools/download/upload_osl_hf.py --repo-id <org/repo> --json-path <local_dataset.json> --split test --revision mainDownloads are placed under <output-dir>/<revision>/<split>.
For Parquet/WebDataset downloads, an existing <split>.json in that directory
is reused without downloading or converting the split again.
Classify clips or event centered samples into predefined categories.
Predict when key events happen in long untrimmed sports videos.
Answer natural-language questions about sports video clips.
Search and retrieve relevant clips or moments from a collection of sports videos. This is part of the roadmap and OSL data model, not a first-class OpenSportsLib training workflow yet.
Generate text descriptions for sports events and temporal segments. This is part of the roadmap and OSL data model, not a first-class OpenSportsLib training workflow yet.
- Prepare your dataset in the expected format
- Select or create a YAML config
- Initialize the task specific model
- Train on your annotations
- Run inference on new data
- Extend the pipeline with your own datasets or models
Use the README for the fast start, then go deeper through:
- Full documentation: https://opensportslab.github.io/opensportslib/
- OSL JSON format: docs/data/osl-json-format.md
- High-level API guide: opensportslib/apis/README.md
- Configuration guide: https://opensportslab.github.io/opensportslib/config/configuration-guide/
- Example configs: examples/configs/
- Quickstart scripts: examples/quickstart/
- Contribution guide: CONTRIBUTING.md
- Developer guide: DEVELOPERS.md
For contributors who want to work from source:
git clone https://github.com/OpenSportsLab/opensportslib.git
cd opensportslib
pip install -e .If you prefer conda:
conda create -n osl python=3.12 pip
conda activate osl
pip install -e .# Install PyTorch (CPU/GPU auto-detected)
opensportslib setup
# Optional: install PyTorch Geometric support
opensportslib setup --pyg
# Optional: install for DALI support
opensportslib setup --dali
# Optional: install the X-VARS-compatible VQA dependency profile
opensportslib setup --vqa_xvars
# Optional: install the Qwen-compatible VQA dependency profile
opensportslib setup --vqa_qwen- Make sure you are branching from
dev - Create your feature or fix branch from
dev - Open a pull request back into
dev
We welcome contributions to OpenSportsLib.
Please check:
These documents describe:
- how to add models and datasets
- coding standards
- training pipeline structure
- how to run and test the framework
OpenSportsLib is available under dual licensing.
AGPL 3.0 for research, academic, and community use.
For proprietary or commercial deployment, please refer to LICENSE-COMMERCIAL.
If you use OpenSportsLib in your research, please cite the project.
@misc{opensportslib,
title={OpenSportsLib},
author={OpenSportsLab},
year={2026},
howpublished={\url{https://github.com/OpenSportsLab/opensportslib}}
}OpenSportsLib is developed within the broader OpenSportsLab effort for sports video understanding.
