opensportslib 0.1.3.dev2__tar.gz → 0.1.3.dev4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {opensportslib-0.1.3.dev2/opensportslib.egg-info → opensportslib-0.1.3.dev4}/PKG-INFO +87 -5
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/README.md +86 -4
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/apis/base_task_model.py +18 -9
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/apis/classification.py +63 -43
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/apis/localization.py +61 -61
- opensportslib-0.1.3.dev4/opensportslib/configs/captioning/encoder_decoder/video_captioning.yaml +136 -0
- opensportslib-0.1.3.dev4/opensportslib/configs/captioning/llava/llava_style.yaml +148 -0
- opensportslib-0.1.3.dev4/opensportslib/configs/classification/default.yaml +125 -0
- opensportslib-0.1.3.dev4/opensportslib/configs/classification/frames_npy/sngar-frames.yaml +171 -0
- opensportslib-0.1.3.dev4/opensportslib/configs/classification/tracking/sngar-tracking.yaml +170 -0
- opensportslib-0.1.3.dev4/opensportslib/configs/classification/video/classification.yaml +178 -0
- opensportslib-0.1.3.dev4/opensportslib/configs/localization/default.yaml +134 -0
- opensportslib-0.1.3.dev4/opensportslib/configs/localization/video/localization-dali.yaml +180 -0
- opensportslib-0.1.3.dev4/opensportslib/configs/localization/video/localization-ocv.yaml +189 -0
- opensportslib-0.1.3.dev4/opensportslib/configs/localization/video_features/localization-calf-resnetpca512.yaml +201 -0
- opensportslib-0.1.3.dev4/opensportslib/configs/localization/video_features/localization-netvladpp-resnetpca512.yaml +192 -0
- opensportslib-0.1.3.dev4/opensportslib/configs/reasoning/multimodal/video_text_fusion.yaml +161 -0
- opensportslib-0.1.3.dev4/opensportslib/configs/retrieval/two_tower/video_text_retrieval.yaml +150 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/__init__.py +22 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/accessors.py +374 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/conflicts.py +130 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/loader.py +77 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/migrate.py +22 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/migrations/__init__.py +5 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/migrations/legacy_to_canonical.py +614 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/runtime_adapter.py +60 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/schema.py +61 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/schemas/__init__.py +6 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/schemas/schema_canonical.py +22 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/schemas/schema_legacy.py +17 -0
- opensportslib-0.1.3.dev4/opensportslib/core/config/validate.py +89 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/loss/builder.py +6 -2
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/optimizer/builder.py +4 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/sampler/weighted_sampler.py +8 -5
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/scheduler/builder.py +3 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/trainer/classification_trainer.py +138 -82
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/trainer/localization_trainer.py +81 -49
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/utils/config.py +51 -42
- opensportslib-0.1.3.dev4/opensportslib/core/utils/config_normalize.py +29 -0
- opensportslib-0.1.3.dev4/opensportslib/core/utils/default_args.py +143 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/utils/load_annotations.py +52 -30
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/utils/video_processing.py +10 -4
- opensportslib-0.1.3.dev4/opensportslib/core/utils/wandb.py +217 -0
- opensportslib-0.1.3.dev4/opensportslib/datasets/builder.py +16 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/datasets/classification_dataset.py +140 -44
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/datasets/localization_dataset.py +243 -103
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/datasets/utils/tracking.py +18 -12
- {opensportslib-0.1.3.dev2/opensportslib/config → opensportslib-0.1.3.dev4/opensportslib/legacy_config}/classification.yaml +4 -4
- {opensportslib-0.1.3.dev2/opensportslib/config → opensportslib-0.1.3.dev4/opensportslib/legacy_config}/localization-e2e-ocv.yaml +1 -1
- {opensportslib-0.1.3.dev2/opensportslib/config → opensportslib-0.1.3.dev4/opensportslib/legacy_config}/localization-json_calf_resnetpca512.yaml +1 -1
- {opensportslib-0.1.3.dev2/opensportslib/config → opensportslib-0.1.3.dev4/opensportslib/legacy_config}/localization-json_netvlad++_resnetpca512.yaml +1 -1
- {opensportslib-0.1.3.dev2/opensportslib/config → opensportslib-0.1.3.dev4/opensportslib/legacy_config}/localization.yaml +5 -6
- {opensportslib-0.1.3.dev2/opensportslib/config → opensportslib-0.1.3.dev4/opensportslib/legacy_config}/sngar-frames.yaml +4 -4
- {opensportslib-0.1.3.dev2/opensportslib/config → opensportslib-0.1.3.dev4/opensportslib/legacy_config}/sngar-tracking.yaml +5 -5
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/metrics/localization_metric.py +15 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/backbones/builder.py +1 -1
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/base/contextaware.py +36 -17
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/base/learnablepooling.py +44 -22
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/base/tracking.py +24 -9
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/base/vars.py +7 -2
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/base/video.py +41 -11
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/base/video_mae.py +20 -5
- opensportslib-0.1.3.dev4/opensportslib/models/builder.py +145 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4/opensportslib.egg-info}/PKG-INFO +87 -5
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib.egg-info/SOURCES.txt +37 -7
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/pyproject.toml +2 -2
- opensportslib-0.1.3.dev4/tests/conftest.py +581 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tests/test_classification_dataset_paths.py +32 -12
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tests/test_classification_trainer_dataloader.py +47 -11
- opensportslib-0.1.3.dev4/tests/test_config_architecture.py +104 -0
- opensportslib-0.1.3.dev4/tests/test_config_split_override_sync.py +37 -0
- opensportslib-0.1.3.dev4/tests/test_pretrained_config_merge_policy.py +223 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tests/test_public_apis_smoke.py +4 -4
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tests/test_task_model_api_contract.py +35 -9
- opensportslib-0.1.3.dev2/opensportslib/core/utils/default_args.py +0 -110
- opensportslib-0.1.3.dev2/opensportslib/core/utils/wandb.py +0 -280
- opensportslib-0.1.3.dev2/opensportslib/datasets/builder.py +0 -42
- opensportslib-0.1.3.dev2/opensportslib/models/builder.py +0 -66
- opensportslib-0.1.3.dev2/tests/conftest.py +0 -377
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/LICENSE +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/LICENSE-COMMERCIAL +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/MANIFEST.in +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/examples/quickstart/basic_classification.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/examples/quickstart/basic_localization.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/__init__.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/apis/__init__.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/cli.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/__init__.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/loss/__init__.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/loss/calf.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/loss/ce.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/loss/combine.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/loss/nll.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/optimizer/__init__.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/scheduler/__init__.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/trainer/__init__.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/utils/checkpoint.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/utils/data.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/utils/ddp.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/utils/lightning.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/core/utils/seed.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/datasets/__init__.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/datasets/utils/__init__.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/metrics/classification_metric.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/__init__.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/base/e2e.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/heads/builder.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/neck/builder.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/utils/common.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/utils/impl/__init__.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/utils/impl/asformer.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/utils/impl/calf.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/utils/impl/gsm.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/utils/impl/gtad.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/utils/impl/tsm.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/utils/litebase.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/utils/modules.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/utils/shift.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/models/utils/utils.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/setup/setup.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/tools/__init__.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/tools/_common.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/tools/hf_transfer.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/tools/osl_json_to_parquet.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib/tools/parquet_to_osl_json.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib.egg-info/dependency_links.txt +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib.egg-info/entry_points.txt +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib.egg-info/requires.txt +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/opensportslib.egg-info/top_level.txt +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/setup.cfg +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tests/test_config_utils_smoke.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tests/test_conversion_tools.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tests/test_hf_transfer_tools.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tests/test_localization_dali_filenames.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tests/test_package_smoke.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tests/test_subset_train_infer_integration.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tools/convert/build_soccernet_gar.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tools/convert/build_soccernet_gar_action_spotting.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tools/convert/osl_json_to_parquet_webdataset.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tools/convert/parquet_webdataset_to_osl_json.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tools/download/download_hf_repo.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tools/download/download_osl_hf.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tools/download/upload_osl_hf.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tools/training/classification.py +0 -0
- {opensportslib-0.1.3.dev2 → opensportslib-0.1.3.dev4}/tools/training/localization.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opensportslib
|
|
3
|
-
Version: 0.1.3.
|
|
3
|
+
Version: 0.1.3.dev4
|
|
4
4
|
Summary: OpenSportsLib is the professional library, designed for advanced video understanding in sports. It provides state-of-the-art tools for action recognition, spotting, retrieval, and captioning, making it ideal for researchers, analysts, and developers working with sports video data.
|
|
5
5
|
Author: Jeet Vora
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -34,6 +34,7 @@ Requires-Dist: pytest-cov; extra == "test"
|
|
|
34
34
|
Dynamic: license-file
|
|
35
35
|
|
|
36
36
|
# OpenSportsLib
|
|
37
|
+
<img src="docs/assets/osl.jpg" height="400">
|
|
37
38
|
|
|
38
39
|
OpenSportsLib is a modular Python library for sports video understanding.
|
|
39
40
|
|
|
@@ -57,6 +58,7 @@ OpenSportsLib is designed for **researchers, ML engineers, and sports analytics
|
|
|
57
58
|
## Quick links
|
|
58
59
|
|
|
59
60
|
- **Documentation:** https://opensportslab.github.io/opensportslib/
|
|
61
|
+
- **OSL JSON format:** https://opensportslab.github.io/opensportslib/data/osl-json-format/
|
|
60
62
|
- **PyPI:** https://pypi.org/project/opensportslib/
|
|
61
63
|
- **Issues:** https://github.com/OpenSportsLab/opensportslib/issues
|
|
62
64
|
|
|
@@ -116,7 +118,82 @@ Use it as the main entry point to find:
|
|
|
116
118
|
See the [Model Zoo](docs/model-zoo.md) for available pretrained models,
|
|
117
119
|
reported scores, datasets, and loading snippets.
|
|
118
120
|
|
|
119
|
-
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Dataset format
|
|
124
|
+
|
|
125
|
+
OpenSportsLib annotation files use the **OSL JSON v2.0** format. A dataset JSON
|
|
126
|
+
contains top-level metadata, a shared `labels` schema, and a `data` array where
|
|
127
|
+
each sample points to one or more inputs.
|
|
128
|
+
|
|
129
|
+
Minimal classification sample:
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"labels": {
|
|
134
|
+
"action": {
|
|
135
|
+
"type": "single_label",
|
|
136
|
+
"labels": ["pass", "shot"]
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"data": [
|
|
140
|
+
{
|
|
141
|
+
"id": "clip_0001",
|
|
142
|
+
"inputs": [
|
|
143
|
+
{
|
|
144
|
+
"type": "video",
|
|
145
|
+
"path": "clips/clip_0001.mp4",
|
|
146
|
+
"fps": 25.0
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
"labels": {
|
|
150
|
+
"action": {
|
|
151
|
+
"label": "shot"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Minimal localization sample:
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"labels": {
|
|
164
|
+
"action": {
|
|
165
|
+
"type": "single_label",
|
|
166
|
+
"labels": ["pass", "shot"]
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"data": [
|
|
170
|
+
{
|
|
171
|
+
"id": "game_0001",
|
|
172
|
+
"inputs": [
|
|
173
|
+
{
|
|
174
|
+
"type": "video",
|
|
175
|
+
"path": "games/game_0001.mp4",
|
|
176
|
+
"fps": 25.0
|
|
177
|
+
}
|
|
178
|
+
],
|
|
179
|
+
"events": [
|
|
180
|
+
{
|
|
181
|
+
"head": "action",
|
|
182
|
+
"label": "pass",
|
|
183
|
+
"position_ms": 1240
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Relative paths in `inputs[].path` are resolved from the split media root in the
|
|
192
|
+
YAML config, for example `DATA.common.splits.train.source_path`. See the full
|
|
193
|
+
[OSL JSON format guide](docs/data/osl-json-format.md) for field definitions,
|
|
194
|
+
multi-modal examples, prediction payloads, and conversion notes.
|
|
195
|
+
|
|
196
|
+
---
|
|
120
197
|
|
|
121
198
|
## Quickstart
|
|
122
199
|
|
|
@@ -223,8 +300,8 @@ from opensportslib.tools import (
|
|
|
223
300
|
### Scripts
|
|
224
301
|
|
|
225
302
|
```bash
|
|
226
|
-
python tools/download_osl_hf.py --repo-id <org/repo> --revision main --split test --format parquet --output-dir downloaded_data
|
|
227
|
-
python tools/upload_osl_hf.py --repo-id <org/repo> --json-path <local_dataset.json> --split test --revision main
|
|
303
|
+
python tools/download/download_osl_hf.py --repo-id <org/repo> --revision main --split test --format parquet --output-dir downloaded_data
|
|
304
|
+
python tools/download/upload_osl_hf.py --repo-id <org/repo> --json-path <local_dataset.json> --split test --revision main
|
|
228
305
|
```
|
|
229
306
|
|
|
230
307
|
Downloads are placed under `<output-dir>/<revision>/<split>`.
|
|
@@ -241,9 +318,13 @@ Predict when key events happen in long untrimmed sports videos.
|
|
|
241
318
|
|
|
242
319
|
### Action Retrieval
|
|
243
320
|
Search and retrieve relevant clips or moments from a collection of sports videos.
|
|
321
|
+
This is part of the roadmap and OSL data model, not a first-class OpenSportsLib
|
|
322
|
+
training workflow yet.
|
|
244
323
|
|
|
245
324
|
### Action Description / Captioning
|
|
246
325
|
Generate text descriptions for sports events and temporal segments.
|
|
326
|
+
This is part of the roadmap and OSL data model, not a first-class OpenSportsLib
|
|
327
|
+
training workflow yet.
|
|
247
328
|
|
|
248
329
|
---
|
|
249
330
|
|
|
@@ -263,8 +344,9 @@ Generate text descriptions for sports events and temporal segments.
|
|
|
263
344
|
Use the README for the fast start, then go deeper through:
|
|
264
345
|
|
|
265
346
|
- Full documentation: https://opensportslab.github.io/opensportslib/
|
|
347
|
+
- OSL JSON format: [docs/data/osl-json-format.md](docs/data/osl-json-format.md)
|
|
266
348
|
- High-level API guide: [opensportslib/apis/README.md](opensportslib/apis/README.md)
|
|
267
|
-
- Configuration guide: https://opensportslab.github.io/opensportslib/
|
|
349
|
+
- Configuration guide: https://opensportslab.github.io/opensportslib/config/configuration-guide/
|
|
268
350
|
- Example configs: [examples/configs/](examples/configs/)
|
|
269
351
|
- Quickstart scripts: [examples/quickstart/](examples/quickstart/)
|
|
270
352
|
- Contribution guide: [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# OpenSportsLib
|
|
2
|
+
<img src="docs/assets/osl.jpg" height="400">
|
|
2
3
|
|
|
3
4
|
OpenSportsLib is a modular Python library for sports video understanding.
|
|
4
5
|
|
|
@@ -22,6 +23,7 @@ OpenSportsLib is designed for **researchers, ML engineers, and sports analytics
|
|
|
22
23
|
## Quick links
|
|
23
24
|
|
|
24
25
|
- **Documentation:** https://opensportslab.github.io/opensportslib/
|
|
26
|
+
- **OSL JSON format:** https://opensportslab.github.io/opensportslib/data/osl-json-format/
|
|
25
27
|
- **PyPI:** https://pypi.org/project/opensportslib/
|
|
26
28
|
- **Issues:** https://github.com/OpenSportsLab/opensportslib/issues
|
|
27
29
|
|
|
@@ -81,7 +83,82 @@ Use it as the main entry point to find:
|
|
|
81
83
|
See the [Model Zoo](docs/model-zoo.md) for available pretrained models,
|
|
82
84
|
reported scores, datasets, and loading snippets.
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Dataset format
|
|
89
|
+
|
|
90
|
+
OpenSportsLib annotation files use the **OSL JSON v2.0** format. A dataset JSON
|
|
91
|
+
contains top-level metadata, a shared `labels` schema, and a `data` array where
|
|
92
|
+
each sample points to one or more inputs.
|
|
93
|
+
|
|
94
|
+
Minimal classification sample:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"labels": {
|
|
99
|
+
"action": {
|
|
100
|
+
"type": "single_label",
|
|
101
|
+
"labels": ["pass", "shot"]
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"data": [
|
|
105
|
+
{
|
|
106
|
+
"id": "clip_0001",
|
|
107
|
+
"inputs": [
|
|
108
|
+
{
|
|
109
|
+
"type": "video",
|
|
110
|
+
"path": "clips/clip_0001.mp4",
|
|
111
|
+
"fps": 25.0
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"labels": {
|
|
115
|
+
"action": {
|
|
116
|
+
"label": "shot"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Minimal localization sample:
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"labels": {
|
|
129
|
+
"action": {
|
|
130
|
+
"type": "single_label",
|
|
131
|
+
"labels": ["pass", "shot"]
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"data": [
|
|
135
|
+
{
|
|
136
|
+
"id": "game_0001",
|
|
137
|
+
"inputs": [
|
|
138
|
+
{
|
|
139
|
+
"type": "video",
|
|
140
|
+
"path": "games/game_0001.mp4",
|
|
141
|
+
"fps": 25.0
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
"events": [
|
|
145
|
+
{
|
|
146
|
+
"head": "action",
|
|
147
|
+
"label": "pass",
|
|
148
|
+
"position_ms": 1240
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Relative paths in `inputs[].path` are resolved from the split media root in the
|
|
157
|
+
YAML config, for example `DATA.common.splits.train.source_path`. See the full
|
|
158
|
+
[OSL JSON format guide](docs/data/osl-json-format.md) for field definitions,
|
|
159
|
+
multi-modal examples, prediction payloads, and conversion notes.
|
|
160
|
+
|
|
161
|
+
---
|
|
85
162
|
|
|
86
163
|
## Quickstart
|
|
87
164
|
|
|
@@ -188,8 +265,8 @@ from opensportslib.tools import (
|
|
|
188
265
|
### Scripts
|
|
189
266
|
|
|
190
267
|
```bash
|
|
191
|
-
python tools/download_osl_hf.py --repo-id <org/repo> --revision main --split test --format parquet --output-dir downloaded_data
|
|
192
|
-
python tools/upload_osl_hf.py --repo-id <org/repo> --json-path <local_dataset.json> --split test --revision main
|
|
268
|
+
python tools/download/download_osl_hf.py --repo-id <org/repo> --revision main --split test --format parquet --output-dir downloaded_data
|
|
269
|
+
python tools/download/upload_osl_hf.py --repo-id <org/repo> --json-path <local_dataset.json> --split test --revision main
|
|
193
270
|
```
|
|
194
271
|
|
|
195
272
|
Downloads are placed under `<output-dir>/<revision>/<split>`.
|
|
@@ -206,9 +283,13 @@ Predict when key events happen in long untrimmed sports videos.
|
|
|
206
283
|
|
|
207
284
|
### Action Retrieval
|
|
208
285
|
Search and retrieve relevant clips or moments from a collection of sports videos.
|
|
286
|
+
This is part of the roadmap and OSL data model, not a first-class OpenSportsLib
|
|
287
|
+
training workflow yet.
|
|
209
288
|
|
|
210
289
|
### Action Description / Captioning
|
|
211
290
|
Generate text descriptions for sports events and temporal segments.
|
|
291
|
+
This is part of the roadmap and OSL data model, not a first-class OpenSportsLib
|
|
292
|
+
training workflow yet.
|
|
212
293
|
|
|
213
294
|
---
|
|
214
295
|
|
|
@@ -228,8 +309,9 @@ Generate text descriptions for sports events and temporal segments.
|
|
|
228
309
|
Use the README for the fast start, then go deeper through:
|
|
229
310
|
|
|
230
311
|
- Full documentation: https://opensportslab.github.io/opensportslib/
|
|
312
|
+
- OSL JSON format: [docs/data/osl-json-format.md](docs/data/osl-json-format.md)
|
|
231
313
|
- High-level API guide: [opensportslib/apis/README.md](opensportslib/apis/README.md)
|
|
232
|
-
- Configuration guide: https://opensportslab.github.io/opensportslib/
|
|
314
|
+
- Configuration guide: https://opensportslab.github.io/opensportslib/config/configuration-guide/
|
|
233
315
|
- Example configs: [examples/configs/](examples/configs/)
|
|
234
316
|
- Quickstart scripts: [examples/quickstart/](examples/quickstart/)
|
|
235
317
|
- Contribution guide: [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
@@ -9,6 +9,7 @@ import uuid
|
|
|
9
9
|
from abc import ABC, abstractmethod
|
|
10
10
|
from typing import Any
|
|
11
11
|
|
|
12
|
+
from opensportslib.core.config.accessors import get_component_name_by_kind
|
|
12
13
|
from opensportslib.core.utils.config import expand, load_config_omega, fetch_and_merge_config_from_HF
|
|
13
14
|
|
|
14
15
|
|
|
@@ -23,6 +24,8 @@ class BaseTaskModel(ABC):
|
|
|
23
24
|
|
|
24
25
|
self.config_path = expand(config)
|
|
25
26
|
self.config = load_config_omega(self.config_path)
|
|
27
|
+
self.last_loaded_weights = None
|
|
28
|
+
self.best_checkpoint = None
|
|
26
29
|
|
|
27
30
|
if weights is not None:
|
|
28
31
|
self.config = fetch_and_merge_config_from_HF(self.config, weights, merge_policy="compatibility")
|
|
@@ -41,15 +44,23 @@ class BaseTaskModel(ABC):
|
|
|
41
44
|
|
|
42
45
|
system_cfg = getattr(self.config, "SYSTEM", None)
|
|
43
46
|
if system_cfg is not None:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
system_paths = getattr(system_cfg, "paths", None)
|
|
48
|
+
base_save_dir = expand(
|
|
49
|
+
getattr(system_paths, "save_dir", None)
|
|
50
|
+
or getattr(system_cfg, "save_dir", None)
|
|
51
|
+
or "./checkpoints"
|
|
52
|
+
)
|
|
53
|
+
model_name = get_component_name_by_kind(self.config, "encoder") or "model"
|
|
48
54
|
run_save_dir = os.path.join(base_save_dir, model_name, self.run_id)
|
|
49
55
|
self.save_dir = run_save_dir
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
if system_paths is not None:
|
|
57
|
+
system_paths.save_dir = run_save_dir
|
|
58
|
+
if hasattr(system_paths, "work_dir"):
|
|
59
|
+
system_paths.work_dir = run_save_dir
|
|
60
|
+
else:
|
|
61
|
+
system_cfg.save_dir = run_save_dir
|
|
62
|
+
if hasattr(system_cfg, "work_dir"):
|
|
63
|
+
system_cfg.work_dir = run_save_dir
|
|
53
64
|
os.makedirs(run_save_dir, exist_ok=True)
|
|
54
65
|
else:
|
|
55
66
|
self.save_dir = expand("./checkpoints")
|
|
@@ -60,8 +71,6 @@ class BaseTaskModel(ABC):
|
|
|
60
71
|
self.model = None
|
|
61
72
|
self.processor = None
|
|
62
73
|
self.trainer = None
|
|
63
|
-
self.best_checkpoint = None
|
|
64
|
-
self.last_loaded_weights = None
|
|
65
74
|
|
|
66
75
|
if weights is not None:
|
|
67
76
|
self.load_weights(weights=weights)
|
|
@@ -4,8 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
6
|
import os
|
|
7
|
+
import json
|
|
7
8
|
|
|
8
9
|
from opensportslib.apis.base_task_model import BaseTaskModel
|
|
10
|
+
from opensportslib.core.config.accessors import (
|
|
11
|
+
get_component_provider_by_kind,
|
|
12
|
+
get_data_modality,
|
|
13
|
+
get_split_annotation_path,
|
|
14
|
+
get_system_gpu_count,
|
|
15
|
+
get_system_seed,
|
|
16
|
+
get_system_use_seed,
|
|
17
|
+
)
|
|
9
18
|
from opensportslib.core.utils.config import expand
|
|
10
19
|
|
|
11
20
|
class ClassificationModel(BaseTaskModel):
|
|
@@ -15,24 +24,13 @@ class ClassificationModel(BaseTaskModel):
|
|
|
15
24
|
if override is not None:
|
|
16
25
|
return expand(override)
|
|
17
26
|
|
|
18
|
-
|
|
19
|
-
split_cfg = getattr(data_cfg, split, None)
|
|
20
|
-
path = getattr(split_cfg, "path", None) if split_cfg is not None else None
|
|
21
|
-
if path:
|
|
22
|
-
return expand(path)
|
|
23
|
-
|
|
24
|
-
annotations_cfg = getattr(data_cfg, "annotations", None)
|
|
25
|
-
path = (
|
|
26
|
-
getattr(annotations_cfg, split, None)
|
|
27
|
-
if annotations_cfg is not None
|
|
28
|
-
else None
|
|
29
|
-
)
|
|
27
|
+
path = get_split_annotation_path(self.config, split)
|
|
30
28
|
if path:
|
|
31
29
|
return expand(path)
|
|
32
30
|
|
|
33
31
|
raise ValueError(
|
|
34
32
|
f"Could not resolve path for split '{split}'. "
|
|
35
|
-
f"Expected DATA.
|
|
33
|
+
f"Expected DATA.common.splits.{split}.annotation_path."
|
|
36
34
|
)
|
|
37
35
|
|
|
38
36
|
# -----------------------------------------------------------------
|
|
@@ -54,6 +52,7 @@ class ClassificationModel(BaseTaskModel):
|
|
|
54
52
|
):
|
|
55
53
|
"""Execute one training/inference job on a single process."""
|
|
56
54
|
import torch
|
|
55
|
+
import wandb
|
|
57
56
|
from opensportslib.core.trainer.classification_trainer import Trainer_Classification
|
|
58
57
|
from opensportslib.core.utils.ddp import ddp_cleanup, ddp_setup
|
|
59
58
|
from opensportslib.core.utils.wandb import init_wandb
|
|
@@ -77,8 +76,8 @@ class ClassificationModel(BaseTaskModel):
|
|
|
77
76
|
use_wandb=use_wandb,
|
|
78
77
|
)
|
|
79
78
|
|
|
80
|
-
if
|
|
81
|
-
set_reproducibility(config
|
|
79
|
+
if get_system_use_seed(config):
|
|
80
|
+
set_reproducibility(get_system_seed(config))
|
|
82
81
|
|
|
83
82
|
is_ddp = world_size > 1
|
|
84
83
|
if is_ddp:
|
|
@@ -100,32 +99,50 @@ class ClassificationModel(BaseTaskModel):
|
|
|
100
99
|
|
|
101
100
|
trainer.model = model
|
|
102
101
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
world_size=world_size,
|
|
112
|
-
)
|
|
113
|
-
if rank == 0 and return_queue is not None:
|
|
114
|
-
best_ckpt = best_ckpt or getattr(trainer.trainer, "best_checkpoint_path", None)
|
|
115
|
-
return_queue.put(best_ckpt)
|
|
116
|
-
|
|
117
|
-
elif mode == "infer":
|
|
118
|
-
test_data = build_dataset(config, test_set, processor, split="test")
|
|
119
|
-
predictions = trainer.infer(
|
|
120
|
-
test_data,
|
|
121
|
-
rank=rank,
|
|
122
|
-
world_size=world_size,
|
|
123
|
-
)
|
|
124
|
-
if rank == 0 and return_queue is not None:
|
|
125
|
-
return_queue.put(predictions)
|
|
102
|
+
modality = get_data_modality(config)
|
|
103
|
+
use_tracking_collate = modality in {"tracking", "tracking_parquet"}
|
|
104
|
+
logging.info(
|
|
105
|
+
"Worker setup | mode=%s | modality=%s | tracking_collate=%s",
|
|
106
|
+
mode,
|
|
107
|
+
modality,
|
|
108
|
+
use_tracking_collate,
|
|
109
|
+
)
|
|
126
110
|
|
|
127
|
-
|
|
128
|
-
|
|
111
|
+
try:
|
|
112
|
+
if mode == "train":
|
|
113
|
+
train_data = build_dataset(config, train_set, processor, split="train")
|
|
114
|
+
valid_data = build_dataset(config, valid_set, processor, split="valid")
|
|
115
|
+
best_ckpt = trainer.train(
|
|
116
|
+
model,
|
|
117
|
+
train_data,
|
|
118
|
+
valid_data,
|
|
119
|
+
rank=rank,
|
|
120
|
+
world_size=world_size,
|
|
121
|
+
)
|
|
122
|
+
if rank == 0 and return_queue is not None:
|
|
123
|
+
best_ckpt = best_ckpt or getattr(trainer.trainer, "best_checkpoint_path", None)
|
|
124
|
+
return_queue.put(best_ckpt)
|
|
125
|
+
|
|
126
|
+
elif mode == "infer":
|
|
127
|
+
test_data = build_dataset(config, test_set, processor, split="test")
|
|
128
|
+
_ = trainer.infer(
|
|
129
|
+
test_data,
|
|
130
|
+
rank=rank,
|
|
131
|
+
world_size=world_size,
|
|
132
|
+
)
|
|
133
|
+
if rank == 0 and return_queue is not None:
|
|
134
|
+
if world_size > 1:
|
|
135
|
+
return_queue.put(getattr(trainer, "predictions_path", None))
|
|
136
|
+
else:
|
|
137
|
+
return_queue.put(getattr(trainer, "predictions_payload", None))
|
|
138
|
+
finally:
|
|
139
|
+
if rank == 0 and use_wandb and getattr(wandb, "run", None) is not None:
|
|
140
|
+
try:
|
|
141
|
+
wandb.finish(quiet=True)
|
|
142
|
+
except Exception:
|
|
143
|
+
pass
|
|
144
|
+
if is_ddp:
|
|
145
|
+
ddp_cleanup()
|
|
129
146
|
|
|
130
147
|
def load_weights(
|
|
131
148
|
self,
|
|
@@ -142,7 +159,7 @@ class ClassificationModel(BaseTaskModel):
|
|
|
142
159
|
loaded = self.trainer.load(weights)
|
|
143
160
|
self.model = loaded[0]
|
|
144
161
|
|
|
145
|
-
if
|
|
162
|
+
if get_component_provider_by_kind(self.config, "encoder") == "huggingface":
|
|
146
163
|
self.processor = loaded[1]
|
|
147
164
|
|
|
148
165
|
self.last_loaded_weights = weights
|
|
@@ -180,11 +197,11 @@ class ClassificationModel(BaseTaskModel):
|
|
|
180
197
|
|
|
181
198
|
effective_weights = weights if weights is not None else self.last_loaded_weights
|
|
182
199
|
|
|
183
|
-
world_size = torch.cuda.device_count() or self.config
|
|
200
|
+
world_size = torch.cuda.device_count() or get_system_gpu_count(self.config)
|
|
184
201
|
use_ddp = use_ddp and world_size > 1
|
|
185
202
|
|
|
186
203
|
ctx = mp.get_context("spawn")
|
|
187
|
-
queue = ctx.
|
|
204
|
+
queue = ctx.SimpleQueue()
|
|
188
205
|
|
|
189
206
|
if use_ddp:
|
|
190
207
|
logging.info(f"Launching DDP on {world_size} GPUs")
|
|
@@ -283,6 +300,9 @@ class ClassificationModel(BaseTaskModel):
|
|
|
283
300
|
)
|
|
284
301
|
|
|
285
302
|
predictions = queue.get()
|
|
303
|
+
if use_ddp and isinstance(predictions, str):
|
|
304
|
+
with open(predictions, encoding="utf-8") as f:
|
|
305
|
+
predictions = json.load(f)
|
|
286
306
|
return predictions
|
|
287
307
|
|
|
288
308
|
def evaluate(
|