opensportslib 0.3.0.dev10__tar.gz → 0.3.0.dev12__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.3.0.dev10/opensportslib.egg-info → opensportslib-0.3.0.dev12}/PKG-INFO +8 -2
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/README.md +7 -1
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/apis/base_task_model.py +2 -1
- opensportslib-0.3.0.dev12/opensportslib/configs/localization/h5_header_distance.yaml +119 -0
- opensportslib-0.3.0.dev12/opensportslib/configs/localization/h5_header_skeleton.yaml +161 -0
- opensportslib-0.3.0.dev12/opensportslib/configs/localization/tracking_action_spotting.yaml +151 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/accessors.py +23 -2
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/loader.py +53 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/trainer/localization_trainer.py +22 -29
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/utils/checkpoint.py +34 -17
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/utils/config.py +18 -1
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/utils/load_annotations.py +14 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/utils/wandb.py +6 -1
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/datasets/classification_dataset.py +8 -2
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/datasets/localization_dataset.py +17 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/datasets/utils/h5_tracking.py +59 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/datasets/utils/tracking.py +16 -12
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/metrics/localization_metric.py +69 -33
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/base/rule_based.py +175 -20
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12/opensportslib.egg-info}/PKG-INFO +8 -2
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib.egg-info/SOURCES.txt +1 -5
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/pyproject.toml +1 -1
- opensportslib-0.3.0.dev12/scripts/run_h5_header_rule_inference.py +869 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_h5_header_skeleton_spotter.py +174 -4
- opensportslib-0.3.0.dev10/opensportslib/configs/localization/h5_header_distance.yaml +0 -93
- opensportslib-0.3.0.dev10/opensportslib/configs/localization/h5_header_distance_angle.yaml +0 -93
- opensportslib-0.3.0.dev10/opensportslib/configs/localization/h5_header_distance_speed.yaml +0 -93
- opensportslib-0.3.0.dev10/opensportslib/configs/localization/h5_header_distance_speed_angle.yaml +0 -93
- opensportslib-0.3.0.dev10/opensportslib/configs/localization/h5_header_rule.yaml +0 -99
- opensportslib-0.3.0.dev10/opensportslib/configs/localization/h5_header_skeleton.yaml +0 -65
- opensportslib-0.3.0.dev10/scripts/run_h5_header_rule_inference.py +0 -65
- opensportslib-0.3.0.dev10/scripts/run_header_spotting_eval.py +0 -495
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/LICENSE +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/LICENSE-COMMERCIAL +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/MANIFEST.in +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/examples/quickstart/basic_classification.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/examples/quickstart/basic_localization.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/examples/quickstart/basic_vqa.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/adaptation/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/adaptation/spotta.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/apis/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/apis/classification.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/apis/localization.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/apis/vqa.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/cli.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/classification/default.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/classification/sngar_frames.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/classification/sngar_tracking.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/classification/video.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/default.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/localization/calf_resnetpca512.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/localization/default.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/localization/e2e_spotta.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/localization/netvladpp_resnetpca512.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/localization/video_dali.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/localization/video_ocv.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/vqa/default.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/vqa/qwen.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/vqa/qwen3_vl_native.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/vqa/qwen_lora.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/vqa/qwen_sngar_frames.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/configs/vqa/xvars.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/conflicts.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/migrate.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/migrations/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/migrations/legacy_to_canonical.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/runtime_adapter.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/schema.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/schemas/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/schemas/schema_canonical.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/schemas/schema_legacy.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/validate.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/loss/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/loss/builder.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/loss/calf.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/loss/ce.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/loss/combine.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/loss/nll.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/optimizer/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/optimizer/builder.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/sampler/weighted_sampler.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/scheduler/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/scheduler/builder.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/trainer/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/trainer/classification_trainer.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/trainer/vqa_trainer.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/utils/config_normalize.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/utils/data.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/utils/ddp.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/utils/default_args.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/utils/hf_runtime.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/utils/lightning.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/utils/seed.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/utils/video_processing.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/datasets/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/datasets/builder.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/datasets/utils/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/datasets/vqa_dataset.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/legacy_config/classification.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/legacy_config/localization-e2e-ocv.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/legacy_config/localization-json_calf_resnetpca512.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/legacy_config/localization-json_netvlad++_resnetpca512.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/legacy_config/localization.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/legacy_config/sngar-frames.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/legacy_config/sngar-tracking.yaml +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/metrics/classification_metric.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/metrics/vqa_metric.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/backbones/builder.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/base/contextaware.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/base/e2e.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/base/learnablepooling.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/base/qwen_vl_native.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/base/qwen_xvars.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/base/tracking.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/base/vars.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/base/video.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/base/video_chatgpt_compat.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/base/video_mae.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/base/xvars_videochatgpt.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/builder.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/heads/builder.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/neck/builder.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/common.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/impl/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/impl/asformer.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/impl/calf.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/impl/gsm.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/impl/gtad.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/impl/tsm.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/litebase.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/modules.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/shift.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/utils.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/vqa_prediction_priors.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/vqa_prompting.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/models/utils/xvars_clip_index.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/setup/setup.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/tools/__init__.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/tools/_common.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/tools/hf_transfer.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/tools/osl_json_to_parquet.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/tools/parquet_to_osl_json.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib.egg-info/dependency_links.txt +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib.egg-info/entry_points.txt +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib.egg-info/requires.txt +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib.egg-info/top_level.txt +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/setup.cfg +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/conftest.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_classification_dataset_paths.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_classification_trainer_dataloader.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_config_architecture.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_config_split_override_sync.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_config_utils_smoke.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_conversion_tools.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_extract_xvars_features.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_h5_header_rule_spotter.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_h5_tracking_dataset.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_hf_transfer_tools.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_localization_dali_filenames.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_localization_hf_backend_override.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_localization_intervals.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_package_smoke.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_pretrained_config_merge_policy.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_public_apis_smoke.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_setup_cli.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_spotta_e2e.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_subset_train_infer_integration.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_task_model_api_contract.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_vqa_api.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_vqa_metrics_semantic.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_vqa_qwen_xvars.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_vqa_training_lora.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tests/test_vqa_xvars_videochatgpt.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/convert/build_sn_vqa_2026_vqa.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/convert/build_soccernet_gar.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/convert/build_soccernet_gar_action_spotting.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/convert/build_soccernet_gar_vqa.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/convert/build_xvars_indexes.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/convert/extract_xvars_clip_features.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/convert/osl_json_to_parquet_webdataset.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/convert/parquet_webdataset_to_osl_json.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/download/download_hf_repo.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/download/download_osl_hf.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/download/upload_osl_hf.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/training/classification.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/training/localization.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/training/vqa.py +0 -0
- {opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/tools/upload/upload_model_hf.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opensportslib
|
|
3
|
-
Version: 0.3.0.
|
|
3
|
+
Version: 0.3.0.dev12
|
|
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
|
|
@@ -76,7 +76,7 @@ OpenSportsLib is designed for **researchers, ML engineers, and sports analytics
|
|
|
76
76
|
### Create conda env
|
|
77
77
|
|
|
78
78
|
```bash
|
|
79
|
-
conda create -n osl python=3.12 pip
|
|
79
|
+
conda create -n osl python=3.12 pip -y
|
|
80
80
|
conda activate osl
|
|
81
81
|
```
|
|
82
82
|
|
|
@@ -92,6 +92,12 @@ pip install opensportslib
|
|
|
92
92
|
pip install --pre opensportslib
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
+
### Source development version
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install -e .
|
|
99
|
+
```
|
|
100
|
+
|
|
95
101
|
### Setup Environment (PyTorch, CUDA aware & Optional Dependencies)
|
|
96
102
|
```bash
|
|
97
103
|
# Install PyTorch (CPU/GPU auto-detected)
|
|
@@ -40,7 +40,7 @@ OpenSportsLib is designed for **researchers, ML engineers, and sports analytics
|
|
|
40
40
|
### Create conda env
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
conda create -n osl python=3.12 pip
|
|
43
|
+
conda create -n osl python=3.12 pip -y
|
|
44
44
|
conda activate osl
|
|
45
45
|
```
|
|
46
46
|
|
|
@@ -56,6 +56,12 @@ pip install opensportslib
|
|
|
56
56
|
pip install --pre opensportslib
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
+
### Source development version
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install -e .
|
|
63
|
+
```
|
|
64
|
+
|
|
59
65
|
### Setup Environment (PyTorch, CUDA aware & Optional Dependencies)
|
|
60
66
|
```bash
|
|
61
67
|
# Install PyTorch (CPU/GPU auto-detected)
|
{opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/apis/base_task_model.py
RENAMED
|
@@ -14,6 +14,7 @@ from opensportslib.core.utils.config import (
|
|
|
14
14
|
expand,
|
|
15
15
|
load_config_omega,
|
|
16
16
|
fetch_and_merge_config_from_HF,
|
|
17
|
+
resolve_config_path,
|
|
17
18
|
resolve_inference_class_metadata,
|
|
18
19
|
)
|
|
19
20
|
|
|
@@ -27,7 +28,7 @@ class BaseTaskModel(ABC):
|
|
|
27
28
|
if config is None:
|
|
28
29
|
raise ValueError("config path is required")
|
|
29
30
|
|
|
30
|
-
self.config_path =
|
|
31
|
+
self.config_path = resolve_config_path(config)
|
|
31
32
|
self.config = load_config_omega(self.config_path)
|
|
32
33
|
self.last_loaded_weights = None
|
|
33
34
|
self.best_checkpoint = None
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Distance-family header spotting.
|
|
2
|
+
#
|
|
3
|
+
# One config for all four distance variants. Pick the variant on the `name:`
|
|
4
|
+
# line under MODEL.components.rule.source, and tune the thresholds under
|
|
5
|
+
# `params:`. Anything left out of `params:` falls back to
|
|
6
|
+
# DEFAULT_HEADER_RULE_PARAMS in opensportslib/models/base/rule_based.py.
|
|
7
|
+
#
|
|
8
|
+
# The skeleton family has its own config, h5_header_skeleton.yaml.
|
|
9
|
+
|
|
10
|
+
TASK: localization
|
|
11
|
+
VERSION: 2
|
|
12
|
+
|
|
13
|
+
SYSTEM:
|
|
14
|
+
paths:
|
|
15
|
+
work_dir: ./outputs/header_spotting_distance
|
|
16
|
+
device: cpu
|
|
17
|
+
gpu:
|
|
18
|
+
count: 0
|
|
19
|
+
|
|
20
|
+
DATA:
|
|
21
|
+
common:
|
|
22
|
+
dataset_name: h5_headers
|
|
23
|
+
# --- CHANGE THESE to point at your tracking data -------------------------
|
|
24
|
+
# data_root and source_path are the directory the manifest's relative paths
|
|
25
|
+
# resolve against. annotation_path is a manifest listing the joints/ball h5
|
|
26
|
+
# pairs to scan; generate one with --combined, or write your own. See
|
|
27
|
+
# docs/headers/README.md.
|
|
28
|
+
data_root: /home/giancos/FIFA_data
|
|
29
|
+
classes:
|
|
30
|
+
- header
|
|
31
|
+
splits:
|
|
32
|
+
test:
|
|
33
|
+
type: H5OSLJsonSpotting
|
|
34
|
+
annotation_path: ./outputs/header_spotting/manifest_all.json
|
|
35
|
+
source_path: /home/giancos/FIFA_data
|
|
36
|
+
dataloader:
|
|
37
|
+
batch_size: 1
|
|
38
|
+
shuffle: false
|
|
39
|
+
num_workers: 0
|
|
40
|
+
pin_memory: false
|
|
41
|
+
inputs:
|
|
42
|
+
tracking:
|
|
43
|
+
modality: player_joints_h5
|
|
44
|
+
representation: raw
|
|
45
|
+
source:
|
|
46
|
+
format: h5
|
|
47
|
+
sampling: {}
|
|
48
|
+
transform: {}
|
|
49
|
+
augmentations: {}
|
|
50
|
+
params: {}
|
|
51
|
+
|
|
52
|
+
MODEL:
|
|
53
|
+
metadata:
|
|
54
|
+
family: RuleBased
|
|
55
|
+
runner:
|
|
56
|
+
type: runner_h5_header_rule
|
|
57
|
+
components:
|
|
58
|
+
rule:
|
|
59
|
+
kind: algorithm
|
|
60
|
+
source:
|
|
61
|
+
provider: opensportslib
|
|
62
|
+
registry: rule_based
|
|
63
|
+
# --- CHANGE THIS to switch variant -------------------------------
|
|
64
|
+
# h5_header_distance no check on the ball path
|
|
65
|
+
# h5_header_distance_angle path must bend by 25 degrees
|
|
66
|
+
# h5_header_distance_speed speed must change by 25 per cent
|
|
67
|
+
# h5_header_distance_speed_angle both
|
|
68
|
+
# The name alone selects the trajectory mode. Setting
|
|
69
|
+
# trajectory_change_mode below has no effect: HEADER_RULE_VARIANTS is
|
|
70
|
+
# applied after these params and overwrites it.
|
|
71
|
+
name: h5_header_distance
|
|
72
|
+
params:
|
|
73
|
+
label: header
|
|
74
|
+
head_name: action
|
|
75
|
+
|
|
76
|
+
# --- contact ------------------------------------------------------
|
|
77
|
+
# A detection needs distance < distance_threshold_m AND confidence >
|
|
78
|
+
# min_confidence, where confidence is 1 - distance/threshold. The two
|
|
79
|
+
# multiply: 0.5 and 0.5 mean the ball must come within 25 cm.
|
|
80
|
+
distance_threshold_m: 0.5
|
|
81
|
+
min_confidence: 0.5
|
|
82
|
+
# Which joints count as the head. Trim to [nose] to see how much the
|
|
83
|
+
# others contribute.
|
|
84
|
+
head_joints: [nose, neck, l_eye, r_eye, l_ear, r_ear]
|
|
85
|
+
# How stale a ball sample may be when matched to a joint row by time.
|
|
86
|
+
ball_tolerance_ms: 60
|
|
87
|
+
|
|
88
|
+
# --- trajectory, used by the angle and speed variants --------------
|
|
89
|
+
# Vectors are built from a ball sample this far before and after the
|
|
90
|
+
# contact, then compared for bend and for speed change.
|
|
91
|
+
trajectory_pre_window_ms: 200
|
|
92
|
+
trajectory_post_window_ms: 200
|
|
93
|
+
trajectory_min_angle_deg: 25.0
|
|
94
|
+
trajectory_min_speed_delta_ratio: 0.25
|
|
95
|
+
# Below this the ball has barely moved and the test is skipped.
|
|
96
|
+
trajectory_min_vector_norm_m: 0.05
|
|
97
|
+
trajectory_use_xy_only: false
|
|
98
|
+
|
|
99
|
+
# --- throw-ins ----------------------------------------------------
|
|
100
|
+
# Contacts nearer the touchline than sideline_exclusion_m are dropped.
|
|
101
|
+
sideline_filter_enabled: true
|
|
102
|
+
pitch_half_width_m: 50.0
|
|
103
|
+
sideline_exclusion_m: 1.0
|
|
104
|
+
|
|
105
|
+
# --- de-duplication -----------------------------------------------
|
|
106
|
+
# One detection per window, keeping the most confident.
|
|
107
|
+
nms_window_ms: 1000
|
|
108
|
+
|
|
109
|
+
# --- output --------------------------------------------------------
|
|
110
|
+
# Diagnostics carry the contact distance, joint, player and the
|
|
111
|
+
# measured trajectory values on every event.
|
|
112
|
+
include_diagnostics: true
|
|
113
|
+
topology: []
|
|
114
|
+
|
|
115
|
+
TRAIN:
|
|
116
|
+
trainer:
|
|
117
|
+
type: trainer_rule_based
|
|
118
|
+
execution:
|
|
119
|
+
enabled: false
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Skeleton-family header spotting.
|
|
2
|
+
#
|
|
3
|
+
# One config for both skeleton variants. Pick the variant on the `name:` line
|
|
4
|
+
# under MODEL.components.rule.source, and tune the thresholds under `params:`.
|
|
5
|
+
# Anything left out falls back to DEFAULT_SKELETON_RULE_PARAMS in
|
|
6
|
+
# opensportslib/models/base/rule_based.py.
|
|
7
|
+
#
|
|
8
|
+
# The numbered checks below match the sequence in docs/headers/README.md. The
|
|
9
|
+
# measured effects come from an 82-configuration sweep on the 2022 final,
|
|
10
|
+
# recorded in header_skeleton_sweep.xlsx; each is the effect of changing that
|
|
11
|
+
# one setting away from the strict defaults.
|
|
12
|
+
|
|
13
|
+
TASK: localization
|
|
14
|
+
VERSION: 2
|
|
15
|
+
|
|
16
|
+
SYSTEM:
|
|
17
|
+
paths:
|
|
18
|
+
work_dir: ./outputs/header_spotting_skeleton
|
|
19
|
+
device: cpu
|
|
20
|
+
gpu:
|
|
21
|
+
count: 0
|
|
22
|
+
|
|
23
|
+
DATA:
|
|
24
|
+
common:
|
|
25
|
+
dataset_name: h5_headers
|
|
26
|
+
# --- CHANGE THESE to point at your tracking data -------------------------
|
|
27
|
+
# data_root and source_path are the directory the manifest's relative paths
|
|
28
|
+
# resolve against. annotation_path is a manifest listing the joints/ball h5
|
|
29
|
+
# pairs to scan; generate one with --combined, or write your own. See
|
|
30
|
+
# docs/headers/README.md.
|
|
31
|
+
data_root: /home/giancos/FIFA_data
|
|
32
|
+
classes:
|
|
33
|
+
- header
|
|
34
|
+
splits:
|
|
35
|
+
test:
|
|
36
|
+
type: H5OSLJsonSpotting
|
|
37
|
+
annotation_path: ./outputs/header_spotting/manifest_all.json
|
|
38
|
+
source_path: /home/giancos/FIFA_data
|
|
39
|
+
dataloader:
|
|
40
|
+
batch_size: 1
|
|
41
|
+
shuffle: false
|
|
42
|
+
num_workers: 0
|
|
43
|
+
pin_memory: false
|
|
44
|
+
inputs:
|
|
45
|
+
tracking:
|
|
46
|
+
modality: player_joints_h5
|
|
47
|
+
representation: raw
|
|
48
|
+
source:
|
|
49
|
+
format: h5
|
|
50
|
+
sampling: {}
|
|
51
|
+
transform: {}
|
|
52
|
+
augmentations: {}
|
|
53
|
+
params: {}
|
|
54
|
+
|
|
55
|
+
MODEL:
|
|
56
|
+
metadata:
|
|
57
|
+
family: RuleBased
|
|
58
|
+
runner:
|
|
59
|
+
type: runner_h5_header_rule
|
|
60
|
+
components:
|
|
61
|
+
rule:
|
|
62
|
+
kind: algorithm
|
|
63
|
+
source:
|
|
64
|
+
provider: opensportslib
|
|
65
|
+
registry: rule_based
|
|
66
|
+
# --- CHANGE THIS to switch variant -------------------------------
|
|
67
|
+
# h5_header_skeleton 91.4% recall, 86.5% precision
|
|
68
|
+
# h5_header_skeleton_recall 97.1% recall, 69.4% precision
|
|
69
|
+
# h5_header_skeleton_max_recall 100% recall, 61.4% precision
|
|
70
|
+
#
|
|
71
|
+
# With either recall variant, SKELETON_RULE_VARIANTS is applied
|
|
72
|
+
# after these params and overwrites twelve of them: head_joints, the
|
|
73
|
+
# five trajectory gates, both height bounds, ankle_height_max_m,
|
|
74
|
+
# dwell_max_frames and nms_window_frames. Setting those below has no
|
|
75
|
+
# effect on that variant. Everything else still applies to both.
|
|
76
|
+
name: h5_header_skeleton
|
|
77
|
+
params:
|
|
78
|
+
label: header
|
|
79
|
+
head_name: action
|
|
80
|
+
|
|
81
|
+
# --- check 4: contact ---------------------------------------------
|
|
82
|
+
# Distance from the ball to the nearest tracked head joint. Each joint
|
|
83
|
+
# is measured separately and the smallest wins; no midpoint is used.
|
|
84
|
+
# Measured: 0.5 gains 5 points of precision and 4.3 of mAP for 2.8 of
|
|
85
|
+
# recall, and is the single best change to these defaults. 0.25
|
|
86
|
+
# collapses recall to 49%.
|
|
87
|
+
head_ball_distance_max_m: 0.4
|
|
88
|
+
# Trim to [nose] to see how much the others contribute. All six help
|
|
89
|
+
# the recall variant, where 77% of detections match on something other
|
|
90
|
+
# than the nose, but cost the strict variant about 4 points of recall.
|
|
91
|
+
head_joints: [nose]
|
|
92
|
+
|
|
93
|
+
# --- check 1: ball height ------------------------------------------
|
|
94
|
+
# Measured: removing this band costs 4.6 points of precision. Worth
|
|
95
|
+
# keeping. Narrowing to 1.5-2.5 costs 10 points of recall.
|
|
96
|
+
ball_height_min_m: 1.3
|
|
97
|
+
ball_height_max_m: 3.0
|
|
98
|
+
# Sentinel marking an untracked coordinate.
|
|
99
|
+
invalid_value: -1.0
|
|
100
|
+
|
|
101
|
+
# --- checks 2 and 3: what the ball did ------------------------------
|
|
102
|
+
# Velocity comes from adjacent frames, acceleration from two frames
|
|
103
|
+
# either side.
|
|
104
|
+
#
|
|
105
|
+
# Measured: only the bend test earns its place. 25 degrees gains about
|
|
106
|
+
# 2 points of precision over 10. The other four are dead weight on this
|
|
107
|
+
# data: velocity_change actively costs recall and precision, while
|
|
108
|
+
# velocity_mag and accel_z_change produce byte-identical output whether
|
|
109
|
+
# on or off, meaning they never fire.
|
|
110
|
+
angle_change_min_deg: 10.0
|
|
111
|
+
velocity_change_min_mps: 2.0
|
|
112
|
+
velocity_mag_min_mps: 1.0
|
|
113
|
+
accel_z_change_min_mps2: 8.0
|
|
114
|
+
incoming_speed_min_mps: 4.0
|
|
115
|
+
|
|
116
|
+
# --- checks 5, 6, 7: the player -------------------------------------
|
|
117
|
+
# Facing is the dot product of the shoulder-line normal with the
|
|
118
|
+
# direction to the ball. Measured: inert at -0.5, it rejects nothing.
|
|
119
|
+
# Raising it to 0.0 costs 18 points of recall, so it is a blunt tool.
|
|
120
|
+
facing_dot_min: -0.5
|
|
121
|
+
# A hand nearer the ball than the head means an arm or a keeper's grab.
|
|
122
|
+
# Measured: worth 2.8 points of precision and free in recall.
|
|
123
|
+
hand_check_enabled: true
|
|
124
|
+
# Both ankles must be below this. Measured: harmful here, removing it
|
|
125
|
+
# improves recall, precision and F1 together.
|
|
126
|
+
ankle_height_max_m: 1.2
|
|
127
|
+
|
|
128
|
+
# --- check 8: dwell --------------------------------------------------
|
|
129
|
+
# Counts frames within dwell_window_frames either side where the head is
|
|
130
|
+
# within the dwell radius. A ball that lingers was carried, not headed.
|
|
131
|
+
# Measured: the strongest gate. Removing it costs 3.8 points of
|
|
132
|
+
# precision; tightening to 3 reaches 94.6% precision at 67% recall.
|
|
133
|
+
dwell_max_frames: 5
|
|
134
|
+
dwell_window_frames: 3
|
|
135
|
+
# The dwell radius is head_ball_distance_max_m * dwell_distance_factor
|
|
136
|
+
# unless dwell_distance_m is set. Set it when widening the contact
|
|
137
|
+
# threshold, or the dwell filter silently tightens with it.
|
|
138
|
+
dwell_distance_factor: 1.2
|
|
139
|
+
dwell_distance_m: null
|
|
140
|
+
|
|
141
|
+
# --- de-duplication --------------------------------------------------
|
|
142
|
+
# One detection per window, keeping the closest contact. Measured: 40
|
|
143
|
+
# gains 1.5 points of precision and 1.3 of mAP; 60 gains 4.3 of
|
|
144
|
+
# precision for 1.9 of recall.
|
|
145
|
+
nms_window_frames: 25
|
|
146
|
+
fps: 50.0
|
|
147
|
+
|
|
148
|
+
# --- output ----------------------------------------------------------
|
|
149
|
+
# Diagnostics carry the contact distance, which head joint matched, the
|
|
150
|
+
# player, the ball height, the dwell count and the trajectory values.
|
|
151
|
+
include_diagnostics: true
|
|
152
|
+
# Added to every position_ms. Leave at 0 unless correcting a known
|
|
153
|
+
# offset between the tracking and the clock you report against.
|
|
154
|
+
position_offset_ms: 0.0
|
|
155
|
+
topology: []
|
|
156
|
+
|
|
157
|
+
TRAIN:
|
|
158
|
+
trainer:
|
|
159
|
+
type: trainer_rule_based
|
|
160
|
+
execution:
|
|
161
|
+
enabled: false
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
SYSTEM:
|
|
2
|
+
paths:
|
|
3
|
+
save_dir: ./checkpoints_as_tracking
|
|
4
|
+
gpu:
|
|
5
|
+
count: 1
|
|
6
|
+
|
|
7
|
+
DATA:
|
|
8
|
+
common:
|
|
9
|
+
dataset_name: SoccerNet-GAR-Spotting-Tracking
|
|
10
|
+
data_root: /home/karkid/PFF/sngar-spotting-tracking-dedup
|
|
11
|
+
classes:
|
|
12
|
+
- PASS
|
|
13
|
+
- HEADER
|
|
14
|
+
- HIGH PASS
|
|
15
|
+
- OUT
|
|
16
|
+
- CROSS
|
|
17
|
+
- THROW IN
|
|
18
|
+
- SHOT
|
|
19
|
+
- PLAYER SUCCESSFUL TACKLE
|
|
20
|
+
- FREE KICK
|
|
21
|
+
- GOAL
|
|
22
|
+
splits:
|
|
23
|
+
train:
|
|
24
|
+
type: TrackingActionSpot
|
|
25
|
+
annotation_path: ${DATA.common.data_root}/annotations_train.json
|
|
26
|
+
source_path: ${DATA.common.data_root}
|
|
27
|
+
dataloader:
|
|
28
|
+
batch_size: 4
|
|
29
|
+
shuffle: true
|
|
30
|
+
num_workers: 16 # graph build is CPU bound
|
|
31
|
+
pin_memory: true
|
|
32
|
+
valid:
|
|
33
|
+
type: TrackingActionSpot
|
|
34
|
+
annotation_path: ${DATA.common.data_root}/annotations_valid.json
|
|
35
|
+
source_path: ${DATA.common.data_root}
|
|
36
|
+
dataloader:
|
|
37
|
+
batch_size: 4
|
|
38
|
+
shuffle: false
|
|
39
|
+
num_workers: 16
|
|
40
|
+
pin_memory: true
|
|
41
|
+
valid_data_frames:
|
|
42
|
+
type: TrackingActionSpotVideo
|
|
43
|
+
annotation_path: ${DATA.common.splits.valid.annotation_path}
|
|
44
|
+
source_path: ${DATA.common.splits.valid.source_path}
|
|
45
|
+
overlap_len: 0
|
|
46
|
+
dataloader:
|
|
47
|
+
batch_size: 1
|
|
48
|
+
shuffle: false
|
|
49
|
+
num_workers: 2
|
|
50
|
+
pin_memory: false
|
|
51
|
+
test:
|
|
52
|
+
type: TrackingActionSpotVideo
|
|
53
|
+
annotation_path: ${DATA.common.data_root}/annotations_test.json
|
|
54
|
+
source_path: ${DATA.common.data_root}
|
|
55
|
+
results: results_spotting_test
|
|
56
|
+
metric: tight
|
|
57
|
+
nms_window: 2
|
|
58
|
+
overlap_len: 270 # 90% of clip_len
|
|
59
|
+
dataloader:
|
|
60
|
+
batch_size: 1
|
|
61
|
+
shuffle: false
|
|
62
|
+
num_workers: 2
|
|
63
|
+
pin_memory: false
|
|
64
|
+
|
|
65
|
+
inputs:
|
|
66
|
+
video:
|
|
67
|
+
modality: tracking_parquet
|
|
68
|
+
representation: raw
|
|
69
|
+
source:
|
|
70
|
+
format: parquet
|
|
71
|
+
sampling:
|
|
72
|
+
epoch_num_frames: 1500000 # 5000 clips/epoch
|
|
73
|
+
clip_len: 300
|
|
74
|
+
extract_fps: 5
|
|
75
|
+
transform:
|
|
76
|
+
normalize: true # x, y, dx, dy, z by the pitch constants below
|
|
77
|
+
augmentations: # train only; the dataset gates on is_eval
|
|
78
|
+
vertical_flip: true
|
|
79
|
+
horizontal_flip: true
|
|
80
|
+
team_flip: true
|
|
81
|
+
params:
|
|
82
|
+
dilate_len: 1
|
|
83
|
+
mixup: false # undefined on graphs; overrides the RGB default
|
|
84
|
+
objects:
|
|
85
|
+
num_objects: 23
|
|
86
|
+
feature_dim: 8
|
|
87
|
+
pitch_half_length: 85.0
|
|
88
|
+
pitch_half_width: 50.0
|
|
89
|
+
max_displacement: 110.0
|
|
90
|
+
max_ball_height: 30.0
|
|
91
|
+
|
|
92
|
+
MODEL:
|
|
93
|
+
metadata:
|
|
94
|
+
family: E2E
|
|
95
|
+
runner:
|
|
96
|
+
type: runner_e2e
|
|
97
|
+
components:
|
|
98
|
+
video_encoder:
|
|
99
|
+
kind: encoder
|
|
100
|
+
source:
|
|
101
|
+
provider: opensportslib
|
|
102
|
+
registry: backbone
|
|
103
|
+
name: graph_conv_seq # per-frame embeddings, not a pooled clip vector
|
|
104
|
+
params:
|
|
105
|
+
# gen GENConv softmax aggregation, learnable t and p
|
|
106
|
+
# gat GATv2Conv four attention heads
|
|
107
|
+
# sageconv SAGEConv mean, max and std aggregation
|
|
108
|
+
# gin GINConv sum aggregation over a two-layer MLP
|
|
109
|
+
# edgeconv EdgeConv max aggregation over node pairs
|
|
110
|
+
# graphconv GraphConv plain add
|
|
111
|
+
encoder: graphconv
|
|
112
|
+
hidden_dim: 64
|
|
113
|
+
num_layers: 20
|
|
114
|
+
dropout: 0.1
|
|
115
|
+
edge_type: positional
|
|
116
|
+
k: 8
|
|
117
|
+
radius: 15.0
|
|
118
|
+
task_head:
|
|
119
|
+
kind: head
|
|
120
|
+
source:
|
|
121
|
+
provider: opensportslib
|
|
122
|
+
registry: head
|
|
123
|
+
name: gru
|
|
124
|
+
|
|
125
|
+
TRAIN:
|
|
126
|
+
trainer:
|
|
127
|
+
type: trainer_e2e
|
|
128
|
+
epochs: 100
|
|
129
|
+
criterion:
|
|
130
|
+
type: CrossEntropyLoss
|
|
131
|
+
optimizer:
|
|
132
|
+
type: AdamWithScaler
|
|
133
|
+
lr: 0.001
|
|
134
|
+
scheduler:
|
|
135
|
+
type: ChainedSchedulerE2E
|
|
136
|
+
acc_grad_iter: 1
|
|
137
|
+
num_epochs: ${TRAIN.epochs}
|
|
138
|
+
warm_up_epochs: 5
|
|
139
|
+
execution:
|
|
140
|
+
enabled: true
|
|
141
|
+
multi_gpu: false
|
|
142
|
+
acc_grad_iter: 1
|
|
143
|
+
base_num_valid_epochs: 30
|
|
144
|
+
start_valid_epoch: 4
|
|
145
|
+
valid_map_every: 10
|
|
146
|
+
criterion_valid: map
|
|
147
|
+
selection:
|
|
148
|
+
monitor: valid_loss
|
|
149
|
+
mode: min
|
|
150
|
+
checkpoint:
|
|
151
|
+
save_best: true
|
{opensportslib-0.3.0.dev10 → opensportslib-0.3.0.dev12}/opensportslib/core/config/accessors.py
RENAMED
|
@@ -182,11 +182,32 @@ def get_split_source_path(cfg: Any, split: str) -> str | None:
|
|
|
182
182
|
return getattr(split_cfg, "source_path", None)
|
|
183
183
|
|
|
184
184
|
|
|
185
|
+
def classes_to_ordered_list(classes: Any) -> list[str]:
|
|
186
|
+
"""Normalise a classes spec to a list ordered by class index.
|
|
187
|
+
|
|
188
|
+
Classes appear either as a list (already in index order) or as a
|
|
189
|
+
``{name: index}`` mapping - the form written into a run's saved
|
|
190
|
+
config.yaml. ``list(mapping)`` returns keys in *insertion* order, and a
|
|
191
|
+
mapping round-tripped through YAML comes back alphabetically sorted, so
|
|
192
|
+
that would silently permute the class<->index mapping when a checkpoint's
|
|
193
|
+
config is reloaded for inference. Always order a mapping by its indices.
|
|
194
|
+
"""
|
|
195
|
+
if classes is None:
|
|
196
|
+
return []
|
|
197
|
+
if OmegaConf is not None and OmegaConf.is_config(classes):
|
|
198
|
+
classes = OmegaConf.to_container(classes, resolve=True)
|
|
199
|
+
if isinstance(classes, dict):
|
|
200
|
+
try:
|
|
201
|
+
return [name for name, _ in sorted(classes.items(), key=lambda kv: int(kv[1]))]
|
|
202
|
+
except (TypeError, ValueError):
|
|
203
|
+
return list(classes)
|
|
204
|
+
return list(classes)
|
|
205
|
+
|
|
206
|
+
|
|
185
207
|
def get_data_classes(cfg: Any) -> list[str]:
|
|
186
208
|
data = _as_dict(getattr(cfg, "DATA", None))
|
|
187
209
|
common = _as_dict(data.get("common"))
|
|
188
|
-
|
|
189
|
-
return list(classes) if classes is not None else []
|
|
210
|
+
return classes_to_ordered_list(common.get("classes", []))
|
|
190
211
|
|
|
191
212
|
|
|
192
213
|
def get_data_num_classes(cfg: Any, default: int = 0) -> int:
|
|
@@ -148,11 +148,64 @@ def _dali_available() -> bool:
|
|
|
148
148
|
return importlib.util.find_spec("nvidia.dali") is not None
|
|
149
149
|
|
|
150
150
|
|
|
151
|
+
# DALI decodes video; any other input modality (tracking parquets, features)
|
|
152
|
+
# has no DALI pipeline and must never be switched onto that backend.
|
|
153
|
+
_DALI_CAPABLE_MODALITIES = {"video", "rgb", "video_mp4"}
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _inputs_are_dali_capable(payload: dict[str, Any]) -> bool:
|
|
157
|
+
"""Whether this config's inputs can be read by DALI at all.
|
|
158
|
+
|
|
159
|
+
A missing/unrecognised modality is treated as video so existing RGB
|
|
160
|
+
configs keep their behaviour; only an explicitly non-video modality
|
|
161
|
+
(e.g. tracking_parquet) opts out.
|
|
162
|
+
"""
|
|
163
|
+
data = payload.get("DATA", {})
|
|
164
|
+
if not isinstance(data, dict):
|
|
165
|
+
return True
|
|
166
|
+
inputs = data.get("inputs", {})
|
|
167
|
+
if not isinstance(inputs, dict) or not inputs:
|
|
168
|
+
return True
|
|
169
|
+
|
|
170
|
+
for spec in inputs.values():
|
|
171
|
+
if not isinstance(spec, dict):
|
|
172
|
+
continue
|
|
173
|
+
modality = spec.get("modality")
|
|
174
|
+
if modality is not None and str(modality).lower() not in _DALI_CAPABLE_MODALITIES:
|
|
175
|
+
return False
|
|
176
|
+
return True
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _declares_opencv_split_types(payload: dict[str, Any]) -> bool:
|
|
180
|
+
"""Whether the config explicitly asks for the OpenCV video datasets."""
|
|
181
|
+
data = payload.get("DATA", {})
|
|
182
|
+
common = data.get("common", {}) if isinstance(data, dict) else {}
|
|
183
|
+
splits = common.get("splits", {}) if isinstance(common, dict) else {}
|
|
184
|
+
if not isinstance(splits, dict):
|
|
185
|
+
return False
|
|
186
|
+
opencv_types = set(_CPU_OPENCV_SPLIT_TYPES.values())
|
|
187
|
+
return any(
|
|
188
|
+
isinstance(cfg, dict) and cfg.get("type") in opencv_types
|
|
189
|
+
for cfg in splits.values()
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
151
193
|
def _preferred_loader_backend(payload: dict[str, Any]) -> str | None:
|
|
152
194
|
system = payload.get("SYSTEM", {})
|
|
153
195
|
if not isinstance(system, dict):
|
|
154
196
|
return None
|
|
155
197
|
|
|
198
|
+
# Selecting DALI for non-video data yields tracking/feature datasets driven
|
|
199
|
+
# through the DALI training branch, which fails with KeyError: 'frame'.
|
|
200
|
+
if not _inputs_are_dali_capable(payload):
|
|
201
|
+
return "opencv"
|
|
202
|
+
|
|
203
|
+
# Likewise honour split types that explicitly name the OpenCV datasets:
|
|
204
|
+
# forcing DALI leaves those types in place (only DALI->OpenCV is remapped
|
|
205
|
+
# below), producing the same mismatched-branch failure.
|
|
206
|
+
if _declares_opencv_split_types(payload):
|
|
207
|
+
return "opencv"
|
|
208
|
+
|
|
156
209
|
mode = str(system.get("device", "auto")).lower()
|
|
157
210
|
if mode == "cpu":
|
|
158
211
|
return "opencv"
|
|
@@ -399,15 +399,21 @@ class Trainer_e2e(Trainer):
|
|
|
399
399
|
|
|
400
400
|
# ---------------- W&B LOG ----------------
|
|
401
401
|
if wandb.run is not None:
|
|
402
|
-
|
|
402
|
+
payload = {
|
|
403
403
|
"epoch": epoch + 1,
|
|
404
404
|
"train/loss": train_loss,
|
|
405
405
|
"valid/loss": valid_loss,
|
|
406
|
-
"valid/mAP": valid_mAP,
|
|
407
406
|
"lr": self.optimizer.param_groups[0]["lr"],
|
|
408
407
|
"best/mAP": self.best_criterion_valid if self.criterion_valid == "map" else None,
|
|
409
408
|
"best/loss": self.best_criterion_valid if self.criterion_valid == "loss" else None,
|
|
410
|
-
}
|
|
409
|
+
}
|
|
410
|
+
# Whole-match mAP only runs every valid_map_every epochs.
|
|
411
|
+
# Logging a placeholder 0 on the other epochs drew a sawtooth
|
|
412
|
+
# collapsing to zero between real measurements; omit the key
|
|
413
|
+
# instead so the chart connects the points that exist.
|
|
414
|
+
if valid_mAP:
|
|
415
|
+
payload["valid/mAP"] = valid_mAP
|
|
416
|
+
wandb.log(payload)
|
|
411
417
|
|
|
412
418
|
if self.save_dir is not None:
|
|
413
419
|
os.makedirs(self.save_dir, exist_ok=True)
|
|
@@ -883,6 +889,9 @@ class Evaluator:
|
|
|
883
889
|
targets_numpy = []
|
|
884
890
|
detections_numpy = []
|
|
885
891
|
closests_numpy = []
|
|
892
|
+
# Rate the dense vectors below end up sampled at; the mAP tolerances
|
|
893
|
+
# are in seconds and must be converted with this same rate.
|
|
894
|
+
eval_framerate = self.extract_fps
|
|
886
895
|
|
|
887
896
|
# ==================================================
|
|
888
897
|
# LOOP
|
|
@@ -975,32 +984,15 @@ class Evaluator:
|
|
|
975
984
|
fps = pred_data_local.get("fps", self.extract_fps)
|
|
976
985
|
|
|
977
986
|
# ---------------- VECTORS ----------------
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
)
|
|
988
|
-
)
|
|
989
|
-
)
|
|
990
|
-
for event in labels:
|
|
991
|
-
frame_candidates.append(
|
|
992
|
-
int(fps * (event["position"] / 1000)) + 1
|
|
993
|
-
)
|
|
994
|
-
for event in predictions:
|
|
995
|
-
if event.get("frame") is not None:
|
|
996
|
-
frame_candidates.append(int(event["frame"]) + 1)
|
|
997
|
-
elif event.get("position") is not None:
|
|
998
|
-
frame_candidates.append(
|
|
999
|
-
int(fps * (int(event["position"]) / 1000)) + 1
|
|
1000
|
-
)
|
|
1001
|
-
vector_size = max(frame_candidates)
|
|
1002
|
-
else:
|
|
1003
|
-
vector_size = game.get("num_frames")
|
|
987
|
+
# Size the dense vectors from the actual content instead of the
|
|
988
|
+
# 90-minute default: a match clock can run well past 90 min
|
|
989
|
+
# (kick-off offset, stoppage, half-time gap) and anything beyond
|
|
990
|
+
# the cap is clamped onto the final bin, silently merging events.
|
|
991
|
+
positions_ms = [a["position"] for a in labels] + [
|
|
992
|
+
p["position"] for p in predictions
|
|
993
|
+
]
|
|
994
|
+
vector_size = int(fps * (max(positions_ms) / 1000)) + 2 if positions_ms else None
|
|
995
|
+
eval_framerate = fps
|
|
1004
996
|
|
|
1005
997
|
dense_labels = label2vector(
|
|
1006
998
|
labels,
|
|
@@ -1033,6 +1025,7 @@ class Evaluator:
|
|
|
1033
1025
|
detections_numpy,
|
|
1034
1026
|
closests_numpy,
|
|
1035
1027
|
INVERSE_EVENT_DICTIONARY,
|
|
1028
|
+
framerate=eval_framerate,
|
|
1036
1029
|
)
|
|
1037
1030
|
else:
|
|
1038
1031
|
logging.warning("No predictions found.")
|