opensportslib 0.3.0.dev7__tar.gz → 0.3.0.dev9__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.
Files changed (183) hide show
  1. {opensportslib-0.3.0.dev7/opensportslib.egg-info → opensportslib-0.3.0.dev9}/PKG-INFO +1 -1
  2. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/apis/base_task_model.py +7 -1
  3. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/apis/classification.py +3 -1
  4. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/apis/localization.py +6 -1
  5. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/vqa/default.yaml +10 -10
  6. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/vqa/qwen.yaml +1 -1
  7. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/vqa/qwen3_vl_native.yaml +1 -1
  8. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/vqa/qwen_lora.yaml +2 -2
  9. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/vqa/xvars.yaml +4 -4
  10. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/accessors.py +45 -0
  11. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/trainer/classification_trainer.py +10 -0
  12. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/utils/config.py +117 -4
  13. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/utils/hf_runtime.py +7 -3
  14. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/datasets/classification_dataset.py +28 -4
  15. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/datasets/vqa_dataset.py +49 -7
  16. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/base/qwen_xvars.py +2 -2
  17. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/base/xvars_videochatgpt.py +58 -3
  18. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9/opensportslib.egg-info}/PKG-INFO +1 -1
  19. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/pyproject.toml +1 -1
  20. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_localization_hf_backend_override.py +148 -0
  21. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_pretrained_config_merge_policy.py +71 -34
  22. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_vqa_api.py +94 -0
  23. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_vqa_qwen_xvars.py +35 -0
  24. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_vqa_xvars_videochatgpt.py +160 -3
  25. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/LICENSE +0 -0
  26. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/LICENSE-COMMERCIAL +0 -0
  27. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/MANIFEST.in +0 -0
  28. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/README.md +0 -0
  29. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/examples/quickstart/basic_classification.py +0 -0
  30. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/examples/quickstart/basic_localization.py +0 -0
  31. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/examples/quickstart/basic_vqa.py +0 -0
  32. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/__init__.py +0 -0
  33. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/apis/__init__.py +0 -0
  34. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/apis/vqa.py +0 -0
  35. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/cli.py +0 -0
  36. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/classification/default.yaml +0 -0
  37. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/classification/sngar_frames.yaml +0 -0
  38. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/classification/sngar_tracking.yaml +0 -0
  39. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/classification/video.yaml +0 -0
  40. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/default.yaml +0 -0
  41. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/localization/calf_resnetpca512.yaml +0 -0
  42. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/localization/default.yaml +0 -0
  43. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/localization/h5_header_distance.yaml +0 -0
  44. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/localization/h5_header_distance_angle.yaml +0 -0
  45. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/localization/h5_header_distance_speed.yaml +0 -0
  46. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/localization/h5_header_distance_speed_angle.yaml +0 -0
  47. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/localization/h5_header_rule.yaml +0 -0
  48. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/localization/h5_header_skeleton.yaml +0 -0
  49. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/localization/netvladpp_resnetpca512.yaml +0 -0
  50. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/localization/video_dali.yaml +0 -0
  51. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/localization/video_ocv.yaml +0 -0
  52. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/configs/vqa/qwen_sngar_frames.yaml +0 -0
  53. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/__init__.py +0 -0
  54. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/__init__.py +0 -0
  55. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/conflicts.py +0 -0
  56. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/loader.py +0 -0
  57. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/migrate.py +0 -0
  58. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/migrations/__init__.py +0 -0
  59. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/migrations/legacy_to_canonical.py +0 -0
  60. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/runtime_adapter.py +0 -0
  61. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/schema.py +0 -0
  62. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/schemas/__init__.py +0 -0
  63. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/schemas/schema_canonical.py +0 -0
  64. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/schemas/schema_legacy.py +0 -0
  65. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/config/validate.py +0 -0
  66. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/loss/__init__.py +0 -0
  67. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/loss/builder.py +0 -0
  68. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/loss/calf.py +0 -0
  69. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/loss/ce.py +0 -0
  70. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/loss/combine.py +0 -0
  71. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/loss/nll.py +0 -0
  72. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/optimizer/__init__.py +0 -0
  73. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/optimizer/builder.py +0 -0
  74. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/sampler/weighted_sampler.py +0 -0
  75. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/scheduler/__init__.py +0 -0
  76. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/scheduler/builder.py +0 -0
  77. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/trainer/__init__.py +0 -0
  78. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/trainer/localization_trainer.py +0 -0
  79. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/trainer/vqa_trainer.py +0 -0
  80. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/utils/checkpoint.py +0 -0
  81. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/utils/config_normalize.py +0 -0
  82. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/utils/data.py +0 -0
  83. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/utils/ddp.py +0 -0
  84. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/utils/default_args.py +0 -0
  85. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/utils/lightning.py +0 -0
  86. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/utils/load_annotations.py +0 -0
  87. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/utils/seed.py +0 -0
  88. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/utils/video_processing.py +0 -0
  89. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/core/utils/wandb.py +0 -0
  90. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/datasets/__init__.py +0 -0
  91. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/datasets/builder.py +0 -0
  92. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/datasets/localization_dataset.py +0 -0
  93. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/datasets/utils/__init__.py +0 -0
  94. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/datasets/utils/h5_tracking.py +0 -0
  95. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/datasets/utils/tracking.py +0 -0
  96. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/legacy_config/classification.yaml +0 -0
  97. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/legacy_config/localization-e2e-ocv.yaml +0 -0
  98. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/legacy_config/localization-json_calf_resnetpca512.yaml +0 -0
  99. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/legacy_config/localization-json_netvlad++_resnetpca512.yaml +0 -0
  100. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/legacy_config/localization.yaml +0 -0
  101. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/legacy_config/sngar-frames.yaml +0 -0
  102. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/legacy_config/sngar-tracking.yaml +0 -0
  103. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/metrics/classification_metric.py +0 -0
  104. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/metrics/localization_metric.py +0 -0
  105. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/metrics/vqa_metric.py +0 -0
  106. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/__init__.py +0 -0
  107. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/backbones/builder.py +0 -0
  108. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/base/contextaware.py +0 -0
  109. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/base/e2e.py +0 -0
  110. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/base/learnablepooling.py +0 -0
  111. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/base/qwen_vl_native.py +0 -0
  112. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/base/rule_based.py +0 -0
  113. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/base/tracking.py +0 -0
  114. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/base/vars.py +0 -0
  115. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/base/video.py +0 -0
  116. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/base/video_chatgpt_compat.py +0 -0
  117. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/base/video_mae.py +0 -0
  118. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/builder.py +0 -0
  119. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/heads/builder.py +0 -0
  120. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/neck/builder.py +0 -0
  121. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/common.py +0 -0
  122. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/impl/__init__.py +0 -0
  123. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/impl/asformer.py +0 -0
  124. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/impl/calf.py +0 -0
  125. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/impl/gsm.py +0 -0
  126. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/impl/gtad.py +0 -0
  127. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/impl/tsm.py +0 -0
  128. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/litebase.py +0 -0
  129. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/modules.py +0 -0
  130. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/shift.py +0 -0
  131. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/utils.py +0 -0
  132. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/vqa_prediction_priors.py +0 -0
  133. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/vqa_prompting.py +0 -0
  134. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/models/utils/xvars_clip_index.py +0 -0
  135. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/setup/setup.py +0 -0
  136. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/tools/__init__.py +0 -0
  137. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/tools/_common.py +0 -0
  138. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/tools/hf_transfer.py +0 -0
  139. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/tools/osl_json_to_parquet.py +0 -0
  140. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib/tools/parquet_to_osl_json.py +0 -0
  141. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib.egg-info/SOURCES.txt +0 -0
  142. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib.egg-info/dependency_links.txt +0 -0
  143. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib.egg-info/entry_points.txt +0 -0
  144. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib.egg-info/requires.txt +0 -0
  145. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/opensportslib.egg-info/top_level.txt +0 -0
  146. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/scripts/run_h5_header_rule_inference.py +0 -0
  147. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/scripts/run_header_spotting_eval.py +0 -0
  148. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/setup.cfg +0 -0
  149. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/conftest.py +0 -0
  150. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_classification_dataset_paths.py +0 -0
  151. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_classification_trainer_dataloader.py +0 -0
  152. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_config_architecture.py +0 -0
  153. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_config_split_override_sync.py +0 -0
  154. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_config_utils_smoke.py +0 -0
  155. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_conversion_tools.py +0 -0
  156. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_extract_xvars_features.py +0 -0
  157. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_h5_header_rule_spotter.py +0 -0
  158. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_h5_header_skeleton_spotter.py +0 -0
  159. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_h5_tracking_dataset.py +0 -0
  160. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_hf_transfer_tools.py +0 -0
  161. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_localization_dali_filenames.py +0 -0
  162. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_package_smoke.py +0 -0
  163. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_public_apis_smoke.py +0 -0
  164. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_setup_cli.py +0 -0
  165. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_subset_train_infer_integration.py +0 -0
  166. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_task_model_api_contract.py +0 -0
  167. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_vqa_metrics_semantic.py +0 -0
  168. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tests/test_vqa_training_lora.py +0 -0
  169. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/convert/build_sn_vqa_2026_vqa.py +0 -0
  170. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/convert/build_soccernet_gar.py +0 -0
  171. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/convert/build_soccernet_gar_action_spotting.py +0 -0
  172. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/convert/build_soccernet_gar_vqa.py +0 -0
  173. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/convert/build_xvars_indexes.py +0 -0
  174. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/convert/extract_xvars_clip_features.py +0 -0
  175. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/convert/osl_json_to_parquet_webdataset.py +0 -0
  176. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/convert/parquet_webdataset_to_osl_json.py +0 -0
  177. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/download/download_hf_repo.py +0 -0
  178. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/download/download_osl_hf.py +0 -0
  179. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/download/upload_osl_hf.py +0 -0
  180. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/training/classification.py +0 -0
  181. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/training/localization.py +0 -0
  182. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/tools/training/vqa.py +0 -0
  183. {opensportslib-0.3.0.dev7 → opensportslib-0.3.0.dev9}/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.dev7
3
+ Version: 0.3.0.dev9
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
@@ -10,7 +10,12 @@ from abc import ABC, abstractmethod
10
10
  from typing import Any
11
11
 
12
12
  from opensportslib.core.config.accessors import get_component_name_by_kind
13
- from opensportslib.core.utils.config import expand, load_config_omega, fetch_and_merge_config_from_HF
13
+ from opensportslib.core.utils.config import (
14
+ expand,
15
+ load_config_omega,
16
+ fetch_and_merge_config_from_HF,
17
+ resolve_inference_class_metadata,
18
+ )
14
19
 
15
20
 
16
21
  class BaseTaskModel(ABC):
@@ -29,6 +34,7 @@ class BaseTaskModel(ABC):
29
34
 
30
35
  if weights is not None:
31
36
  self.config = fetch_and_merge_config_from_HF(self.config, weights, merge_policy="compatibility")
37
+ self.config = resolve_inference_class_metadata(self.config)
32
38
  self.last_loaded_weights = weights
33
39
  self.best_checkpoint = weights
34
40
 
@@ -15,7 +15,7 @@ from opensportslib.core.config.accessors import (
15
15
  get_system_seed,
16
16
  get_system_use_seed,
17
17
  )
18
- from opensportslib.core.utils.config import expand
18
+ from opensportslib.core.utils.config import expand, resolve_inference_class_metadata
19
19
 
20
20
 
21
21
  def _is_tracking_graph_modality(modality):
@@ -269,6 +269,7 @@ class ClassificationModel(BaseTaskModel):
269
269
  test_set = self._resolve_split_path("test", test_set)
270
270
 
271
271
  self.config = resolve_config_omega(self.config, weights=weights)
272
+ self.config = resolve_inference_class_metadata(self.config)
272
273
  logging.info("Configuration:")
273
274
  logging.info(self.config)
274
275
 
@@ -335,6 +336,7 @@ class ClassificationModel(BaseTaskModel):
335
336
  test_set = self._resolve_split_path("test", test_set)
336
337
 
337
338
  self.config = resolve_config_omega(self.config, weights=weights)
339
+ self.config = resolve_inference_class_metadata(self.config)
338
340
  logging.info("Configuration:")
339
341
  logging.info(self.config)
340
342
  if predictions is None:
@@ -18,7 +18,7 @@ from opensportslib.core.config.accessors import (
18
18
  set_loader_backend,
19
19
  get_model_family,
20
20
  )
21
- from opensportslib.core.utils.config import expand
21
+ from opensportslib.core.utils.config import expand, resolve_inference_class_metadata
22
22
  from opensportslib.core.config.loader import _dali_available
23
23
 
24
24
 
@@ -276,6 +276,7 @@ class LocalizationModel(BaseTaskModel):
276
276
  self._set_split_path("valid_data_frames", valid_set)
277
277
 
278
278
  self.config = resolve_config_omega(self.config, weights=weights)
279
+ self.config = resolve_inference_class_metadata(self.config)
279
280
  effective_weights = weights if weights is not None else self.last_loaded_weights
280
281
  self._adapt_hf_backend_for_device(effective_weights)
281
282
  check_config(self.config, split="train")
@@ -389,9 +390,11 @@ class LocalizationModel(BaseTaskModel):
389
390
  self._set_split_path("test", test_set)
390
391
 
391
392
  self.config = resolve_config_omega(self.config, weights=weights)
393
+ self.config = resolve_inference_class_metadata(self.config)
392
394
  effective_weights = weights if weights is not None else self.last_loaded_weights
393
395
  self._adapt_hf_backend_for_device(effective_weights)
394
396
  check_config(self.config, split="test")
397
+ self.config = resolve_inference_class_metadata(self.config)
395
398
  self.config.infer_split = whether_infer_split(get_split_cfg(self.config, "test"))
396
399
 
397
400
  init_wandb(
@@ -459,9 +462,11 @@ class LocalizationModel(BaseTaskModel):
459
462
  test_set = self._resolve_split_path("test", test_set)
460
463
  self._set_split_path("test", test_set)
461
464
  self.config = resolve_config_omega(self.config, weights=weights)
465
+ self.config = resolve_inference_class_metadata(self.config)
462
466
  effective_weights = weights if weights is not None else self.last_loaded_weights
463
467
  self._adapt_hf_backend_for_device(effective_weights)
464
468
  check_config(self.config, split="test")
469
+ self.config = resolve_inference_class_metadata(self.config)
465
470
  self.config.infer_split = whether_infer_split(get_split_cfg(self.config, "test"))
466
471
 
467
472
  init_wandb(
@@ -15,16 +15,16 @@ SYSTEM:
15
15
 
16
16
  DATA:
17
17
  common:
18
- dataset_name: OSL-XFoul
19
- data_root: /home/vorajv/dataset/OSL-XFoul
20
- feature_index: /home/vorajv/dataset/OSL-XFoul/feature_index.json
21
- prediction_index: /home/vorajv/dataset/OSL-XFoul/prediction_index.json
18
+ dataset_name: dataset_name
19
+ data_root: ./dataset/dataset_name
20
+ feature_index: ./dataset/feature_index.json
21
+ prediction_index: ./dataset/prediction_index.json
22
22
  runtime:
23
23
  loader_backend: opencv
24
24
  splits:
25
25
  train:
26
- annotation_path: /home/vorajv/dataset/OSL-XFoul/train.json
27
- source_path: /home/vorajv/dataset/OSL-XFoul
26
+ annotation_path: ./dataset//train.json
27
+ source_path: ./dataset/
28
28
  dataloader:
29
29
  batch_size: 1
30
30
  shuffle: true
@@ -33,8 +33,8 @@ DATA:
33
33
  mp_context: spawn
34
34
  persistent_workers: false
35
35
  valid:
36
- annotation_path: /home/vorajv/dataset/OSL-XFoul/valid.json
37
- source_path: /home/vorajv/dataset/OSL-XFoul
36
+ annotation_path: ./dataset/valid.json
37
+ source_path: ./dataset/
38
38
  dataloader:
39
39
  batch_size: 1
40
40
  shuffle: false
@@ -43,8 +43,8 @@ DATA:
43
43
  mp_context: spawn
44
44
  persistent_workers: false
45
45
  test:
46
- annotation_path: /home/vorajv/dataset/OSL-XFoul/test.json
47
- source_path: /home/vorajv/dataset/OSL-XFoul
46
+ annotation_path: ./dataset/test.json
47
+ source_path: ./dataset/
48
48
  dataloader:
49
49
  batch_size: 1
50
50
  shuffle: false
@@ -10,7 +10,7 @@ MODEL:
10
10
  provider: opensportslib
11
11
  name: xvars_clip_features
12
12
  load:
13
- weights_path: /home/vorajv/X-VARS/weights/14_model.pth.tar
13
+ weights_path: OpenSportsLab/trained-clip-vit-large-patch14
14
14
  params:
15
15
  feature_source: indexed_or_raw_clip
16
16
  vision_tower: openai/clip-vit-large-patch14
@@ -1,6 +1,6 @@
1
1
  SYSTEM:
2
2
  paths:
3
- save_dir: ./checkpoints_vqa_qwen3_vl_native
3
+ save_dir: ./checkpoints_vqa_qwen3_vl
4
4
  gpu:
5
5
  count: 4
6
6
  id: null
@@ -1,6 +1,6 @@
1
1
  SYSTEM:
2
2
  paths:
3
- save_dir: ./checkpoints_vqa_qwen_lora
3
+ save_dir: ./checkpoints_vqa_qwen
4
4
  gpu:
5
5
  count: 4
6
6
 
@@ -12,7 +12,7 @@ MODEL:
12
12
  provider: opensportslib
13
13
  name: xvars_clip_features
14
14
  load:
15
- weights_path: /home/vorajv/X-VARS/weights/14_model.pth.tar
15
+ weights_path: OpenSportsLab/trained-clip-vit-large-patch14
16
16
  params:
17
17
  feature_source: indexed_or_raw_clip
18
18
  vision_tower: openai/clip-vit-large-patch14
@@ -1,6 +1,6 @@
1
1
  SYSTEM:
2
2
  paths:
3
- save_dir: ./checkpoints_vqa_lora
3
+ save_dir: ./checkpoints_vqa_xvars_lora
4
4
  gpu:
5
5
  count: 4
6
6
 
@@ -10,9 +10,9 @@ MODEL:
10
10
  kind: encoder
11
11
  source:
12
12
  provider: opensportslib
13
- # XVARS-trained classifier weights to load into that architecture
13
+ # X-VARS visual checkpoint: local file path or HF model repo ID.
14
14
  load:
15
- weights_path: /home/vorajv/X-VARS/weights/14_model.pth.tar
15
+ weights_path: OpenSportsLab/trained-clip-vit-large-patch14
16
16
  params:
17
17
  # CLIP architecture and image processor to instantiate.
18
18
  feature_source: indexed_or_raw_clip
@@ -31,7 +31,7 @@ MODEL:
31
31
  source:
32
32
  provider: opensportslib
33
33
  params:
34
- repo_id: /home/vorajv/X-VARS/weights/base_model_videoChatGPT
34
+ repo_id: OpenSportsLab/base_model_videoChatGPT
35
35
  overrides: {}
36
36
  metadata:
37
37
  backend: xvars_videochatgpt
@@ -194,6 +194,12 @@ def get_data_num_classes(cfg: Any, default: int = 0) -> int:
194
194
  if classes:
195
195
  return len(classes)
196
196
 
197
+ data = _as_dict(getattr(cfg, "DATA", None))
198
+ common = _as_dict(data.get("common"))
199
+ common_num_classes = common.get("num_classes")
200
+ if common_num_classes is not None:
201
+ return int(common_num_classes)
202
+
197
203
  input_cfg = get_input_cfg(cfg)
198
204
  params = _as_dict(input_cfg.get("params"))
199
205
  num_classes = params.get("num_classes")
@@ -222,8 +228,47 @@ def set_data_classes(cfg: Any, classes: list[str]) -> None:
222
228
  common = _ensure_child(data, "common")
223
229
  if isinstance(common, dict):
224
230
  common["classes"] = list(classes)
231
+ common["num_classes"] = len(classes)
225
232
  else:
226
233
  setattr(common, "classes", list(classes))
234
+ setattr(common, "num_classes", len(classes))
235
+
236
+
237
+ def set_data_num_classes(cfg: Any, num_classes: int | None) -> None:
238
+ if num_classes is None:
239
+ return
240
+
241
+ data = getattr(cfg, "DATA", None)
242
+ if data is None:
243
+ data = SimpleNamespace()
244
+ setattr(cfg, "DATA", data)
245
+
246
+ common = _ensure_child(data, "common")
247
+ if isinstance(common, dict):
248
+ common["num_classes"] = int(num_classes)
249
+ else:
250
+ setattr(common, "num_classes", int(num_classes))
251
+
252
+
253
+ def get_data_runtime(cfg: Any) -> dict[str, Any]:
254
+ data = _as_dict(getattr(cfg, "DATA", None))
255
+ common = _as_dict(data.get("common"))
256
+ runtime = _as_dict(common.get("runtime"))
257
+ return runtime
258
+
259
+
260
+ def set_data_runtime_value(cfg: Any, key: str, value: Any) -> None:
261
+ data = getattr(cfg, "DATA", None)
262
+ if data is None:
263
+ data = SimpleNamespace()
264
+ setattr(cfg, "DATA", data)
265
+
266
+ common = _ensure_child(data, "common")
267
+ runtime = _ensure_child(common, "runtime")
268
+ if isinstance(runtime, dict):
269
+ runtime[key] = value
270
+ else:
271
+ setattr(runtime, key, value)
227
272
 
228
273
 
229
274
  def get_input_cfg(cfg: Any, input_name: str | None = None) -> dict[str, Any]:
@@ -1219,6 +1219,11 @@ class Trainer_Classification:
1219
1219
  sid = item["id"]
1220
1220
  gt_label = item["labels"]["action"]["label"]
1221
1221
  if gt_label not in exclude_labels:
1222
+ if gt_label not in label_to_idx:
1223
+ raise ValueError(
1224
+ "Ground-truth label is not present in the resolved inference class list: "
1225
+ f"{gt_label!r}."
1226
+ )
1222
1227
  gt_dict[sid] = label_to_idx[gt_label]
1223
1228
 
1224
1229
  preds = []
@@ -1230,6 +1235,11 @@ class Trainer_Classification:
1230
1235
  continue
1231
1236
 
1232
1237
  pred_label = item["labels"]["action"]["label"]
1238
+ if pred_label not in label_to_idx:
1239
+ raise ValueError(
1240
+ "Predicted label is not present in the resolved inference class list: "
1241
+ f"{pred_label!r}."
1242
+ )
1233
1243
 
1234
1244
  preds.append(label_to_idx[pred_label])
1235
1245
  labels.append(gt_dict[sid])
@@ -2,11 +2,20 @@ import os
2
2
  import re
3
3
  import json
4
4
  import gzip
5
+ import logging
5
6
  try:
6
7
  import yaml
7
8
  except ModuleNotFoundError: # pragma: no cover - runtime compatibility
8
9
  import yaml_compat as yaml
9
10
 
11
+ from opensportslib.core.config.accessors import (
12
+ get_data_classes,
13
+ get_data_num_classes,
14
+ get_data_runtime,
15
+ set_data_classes,
16
+ set_data_num_classes,
17
+ set_data_runtime_value,
18
+ )
10
19
  from opensportslib.core.config import (
11
20
  load_config as _load_config,
12
21
  load_config_omega as _load_config_omega,
@@ -225,6 +234,108 @@ def is_local_path(p):
225
234
  )
226
235
 
227
236
 
237
+ def _extract_class_metadata(data_section):
238
+ if not isinstance(data_section, dict):
239
+ return None, None
240
+
241
+ common = data_section.get("common", {}) if isinstance(data_section.get("common", {}), dict) else {}
242
+ classes = common.get("classes")
243
+ if classes is not None:
244
+ classes = list(classes)
245
+
246
+ num_classes = common.get("num_classes")
247
+ if num_classes is None:
248
+ inputs = data_section.get("inputs", {})
249
+ if isinstance(inputs, dict):
250
+ for input_cfg in inputs.values():
251
+ if not isinstance(input_cfg, dict):
252
+ continue
253
+ params = input_cfg.get("params", {})
254
+ if isinstance(params, dict) and params.get("num_classes") is not None:
255
+ num_classes = params.get("num_classes")
256
+ break
257
+
258
+ if num_classes is None and classes is not None:
259
+ num_classes = len(classes)
260
+
261
+ return classes, num_classes
262
+
263
+
264
+ def _cache_pretrained_class_metadata(target_dict, loaded_dict):
265
+ if not isinstance(target_dict, dict) or not isinstance(loaded_dict, dict):
266
+ return
267
+
268
+ loaded_data = loaded_dict.get("DATA", {})
269
+ pretrained_classes, pretrained_num_classes = _extract_class_metadata(loaded_data)
270
+ if pretrained_classes is None and pretrained_num_classes is None:
271
+ return
272
+
273
+ data = target_dict.setdefault("DATA", {})
274
+ if not isinstance(data, dict):
275
+ return
276
+ common = data.setdefault("common", {})
277
+ if not isinstance(common, dict):
278
+ return
279
+ runtime = common.setdefault("runtime", {})
280
+ if not isinstance(runtime, dict):
281
+ return
282
+
283
+ if pretrained_classes is not None:
284
+ runtime["pretrained_classes"] = list(pretrained_classes)
285
+ if pretrained_num_classes is not None:
286
+ runtime["pretrained_num_classes"] = int(pretrained_num_classes)
287
+
288
+
289
+ def resolve_inference_class_metadata(cfg):
290
+ runtime = get_data_runtime(cfg)
291
+ pretrained_classes = runtime.get("pretrained_classes")
292
+ pretrained_num_classes = runtime.get("pretrained_num_classes")
293
+
294
+ local_classes = get_data_classes(cfg)
295
+ local_num_classes = get_data_num_classes(cfg, default=0)
296
+
297
+ chosen_classes = None
298
+ chosen_num_classes = None
299
+ source = None
300
+
301
+ if pretrained_classes:
302
+ chosen_classes = list(pretrained_classes)
303
+ chosen_num_classes = len(chosen_classes)
304
+ source = "model"
305
+ if local_classes and list(local_classes) != chosen_classes:
306
+ logging.warning(
307
+ "Inference class mismatch: local config classes differ from pretrained model classes. "
308
+ "Using pretrained model classes."
309
+ )
310
+ elif pretrained_num_classes is not None:
311
+ chosen_num_classes = int(pretrained_num_classes)
312
+ source = "model"
313
+ if local_num_classes and int(local_num_classes) != chosen_num_classes:
314
+ logging.warning(
315
+ "Inference class-count mismatch: local config num_classes=%s, pretrained model num_classes=%s. "
316
+ "Using pretrained model class count.",
317
+ local_num_classes,
318
+ chosen_num_classes,
319
+ )
320
+ elif local_classes:
321
+ chosen_classes = list(local_classes)
322
+ chosen_num_classes = len(chosen_classes)
323
+ source = "local"
324
+ elif local_num_classes:
325
+ chosen_num_classes = int(local_num_classes)
326
+ source = "local"
327
+ else:
328
+ source = "annotation"
329
+
330
+ if chosen_classes is not None:
331
+ set_data_classes(cfg, chosen_classes)
332
+ if chosen_num_classes is not None:
333
+ set_data_num_classes(cfg, chosen_num_classes)
334
+ set_data_runtime_value(cfg, "inference_class_source", source)
335
+ set_data_runtime_value(cfg, "inference_model_classes_authoritative", source == "model")
336
+ return cfg
337
+
338
+
228
339
  def fetch_and_merge_config_from_HF(
229
340
  target_config, weights, hf_token=None, merge_policy="full"
230
341
  ):
@@ -275,6 +386,7 @@ def fetch_and_merge_config_from_HF(
275
386
  loaded_dict = namespace_to_dict(loaded_cfg)
276
387
 
277
388
  _warn_critical_config_conflicts(target_dict, loaded_dict)
389
+ _cache_pretrained_class_metadata(target_dict, loaded_dict)
278
390
 
279
391
  if merge_policy == "compatibility":
280
392
  # Keep local runtime config as source of truth. Pull only compatibility-
@@ -315,8 +427,6 @@ def fetch_and_merge_config_from_HF(
315
427
 
316
428
 
317
429
  def _warn_critical_config_conflicts(target_dict, loaded_dict):
318
- import logging
319
-
320
430
  local_data = target_dict.get("DATA", {}) if isinstance(target_dict, dict) else {}
321
431
  hf_data = loaded_dict.get("DATA", {}) if isinstance(loaded_dict, dict) else {}
322
432
 
@@ -335,7 +445,7 @@ def _warn_critical_config_conflicts(target_dict, loaded_dict):
335
445
  ):
336
446
  logging.warning(
337
447
  "Config mismatch: DATA.num_classes local=%s hf=%s. "
338
- "Keeping local runtime config values.",
448
+ "Inference may use pretrained model class metadata.",
339
449
  local_num_classes,
340
450
  hf_num_classes,
341
451
  )
@@ -355,9 +465,12 @@ def _warn_critical_config_conflicts(target_dict, loaded_dict):
355
465
  ):
356
466
  logging.warning(
357
467
  "Config mismatch: DATA.classes differs between local and HF config. "
358
- "Keeping local runtime config values.",
468
+ "Inference may use pretrained model classes.",
359
469
  )
360
470
 
471
+
472
+ fetch_and_merge_pretrained_config = fetch_and_merge_config_from_HF
473
+
361
474
  def save_config(config_obj, path):
362
475
  """Save the configuration object to a YAML file."""
363
476
  from omegaconf import DictConfig, OmegaConf
@@ -234,12 +234,16 @@ def has_peft_adapter_artifacts(adapter_path: str | None) -> bool:
234
234
 
235
235
  def load_peft_adapter_if_available(model, adapter_path: str | None):
236
236
  """Load a PEFT adapter into a model when real adapter artifacts exist."""
237
- if not has_peft_adapter_artifacts(adapter_path):
237
+ if not adapter_path:
238
+ return model, "not_found"
239
+ is_local_dir = os.path.isdir(adapter_path)
240
+ if is_local_dir and not has_peft_adapter_artifacts(adapter_path):
238
241
  return model, "not_found"
239
242
  if not optional_package_available("peft"):
240
243
  logger.warning(
241
- "PEFT adapter artifacts found but optional dependency 'peft' is not installed; "
242
- "continuing with base decoder."
244
+ "PEFT adapter requested but optional dependency 'peft' is not installed; "
245
+ "continuing with base decoder. adapter_path=%s",
246
+ adapter_path,
243
247
  )
244
248
  return model, "missing_peft"
245
249
 
@@ -13,6 +13,7 @@ label mapping, and class-weight computation.
13
13
 
14
14
  import os
15
15
  import random
16
+ import logging
16
17
 
17
18
  import numpy as np
18
19
  import torch
@@ -27,16 +28,19 @@ from opensportslib.core.config.accessors import (
27
28
  get_component_provider_by_kind,
28
29
  get_data_classes,
29
30
  get_data_modality,
31
+ get_data_runtime,
30
32
  get_data_augmentations,
31
33
  get_data_params,
32
34
  get_data_sampling,
33
35
  set_data_classes,
36
+ set_data_num_classes,
34
37
  get_data_transform,
35
38
  get_split_source_path,
36
39
  )
37
40
 
38
41
 
39
42
  H5_TRACKING_MODALITIES = {"player_centroids_h5", "player_joints_h5", "tracking_h5"}
43
+ logger = logging.getLogger(__name__)
40
44
 
41
45
 
42
46
  # -------------------------------------------------------------
@@ -145,14 +149,34 @@ class ClassificationDataset(Dataset):
145
149
 
146
150
  # invert to id -> name and propagate into the config so
147
151
  # downstream components (metrics, logging) can look it up.
148
- self.label_map = {v: k for k, v in self.label_map.items()}
149
- set_data_classes(self.config, list(self.label_map.values()))
152
+ annotation_label_map = {v: k for k, v in self.label_map.items()}
153
+ runtime = get_data_runtime(self.config)
154
+ inference_source = str(runtime.get("inference_class_source") or "").strip().lower()
155
+ configured_classes = list(get_data_classes(self.config))
156
+ configured_label_map = {idx: name for idx, name in enumerate(configured_classes)}
157
+
158
+ if split in {"test", "infer"} and inference_source in {"model", "local"} and configured_classes:
159
+ self.label_map = configured_label_map
160
+ set_data_num_classes(self.config, len(configured_classes))
161
+
162
+ annotation_classes = [annotation_label_map[idx] for idx in sorted(annotation_label_map.keys())]
163
+ if annotation_classes != configured_classes:
164
+ logger.warning(
165
+ "Inference annotation labels differ from resolved %s classes. "
166
+ "Using resolved runtime classes for predictions.",
167
+ inference_source,
168
+ )
169
+ for sample in self.samples:
170
+ sample.pop("label", None)
171
+ self.has_labels = len(self.samples) > 0 and "label" in self.samples[0]
172
+ else:
173
+ self.label_map = annotation_label_map
174
+ set_data_classes(self.config, list(self.label_map.values()))
175
+ self.has_labels = len(self.samples) > 0 and "label" in self.samples[0]
150
176
 
151
177
  print(len(get_data_classes(self.config)), "classes:", get_data_classes(self.config))
152
178
  print("Label Map : ", self.label_map)
153
179
 
154
- self.has_labels = len(self.samples) > 0 and "label" in self.samples[0]
155
-
156
180
  # -- Sampling / loss weights ------------------------------------------
157
181
 
158
182
  def _normalized_label_tensor(self):
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import json
6
+ import logging
6
7
  import os
7
8
  import pickle
8
9
  import random
@@ -22,6 +23,8 @@ from opensportslib.core.config.accessors import (
22
23
  from opensportslib.models.utils.vqa_prediction_priors import build_prediction_prior_text
23
24
  from opensportslib.models.utils.xvars_clip_index import load_feature_index, load_prediction_index, validate_xvars_feature_tensor
24
25
 
26
+ logger = logging.getLogger(__name__)
27
+
25
28
 
26
29
  class VQADataset(Dataset):
27
30
  """Flatten VQA annotations into single question-answer training samples."""
@@ -66,16 +69,18 @@ class VQADataset(Dataset):
66
69
  feature_source = get_vqa_feature_source(config, default="indexed")
67
70
  if not self.native_vl and feature_backend != "xvars_clip":
68
71
  raise ValueError(f"Unsupported VQA feature backend '{feature_backend}'. Expected 'xvars_clip'.")
69
- require_feature_index = (not self.native_vl) and feature_source in {"indexed", ""}
70
- if require_feature_index and not feature_index_path:
72
+ strict_feature_index = (not self.native_vl) and feature_source in {"indexed", ""}
73
+ fallback_feature_index = (not self.native_vl) and feature_source in {"indexed_or_raw", "indexed_or_raw_clip"}
74
+ if strict_feature_index and not feature_index_path:
71
75
  raise ValueError("Missing required config key DATA.common.feature_index for VQA xvars_clip mode.")
72
76
  self.feature_source = feature_source
73
77
  self.feature_mode = get_vqa_xvars_feature_mode(config, default="strict_xvars")
74
78
  self.expected_feature_tokens = get_xvars_train_video_token_len(config)
75
- self.feature_index = (
76
- load_feature_index(os.path.abspath(os.path.expanduser(feature_index_path)), split=split)
77
- if feature_index_path
78
- else {}
79
+ self.feature_index = self._load_feature_index(
80
+ feature_index_path,
81
+ split=split,
82
+ strict=strict_feature_index,
83
+ allow_missing=fallback_feature_index,
79
84
  )
80
85
  self.prediction_index = (
81
86
  load_prediction_index(os.path.abspath(os.path.expanduser(prediction_index_path)), split=split)
@@ -94,7 +99,7 @@ class VQADataset(Dataset):
94
99
  frame_paths = self._resolve_frame_paths(item, source_root)
95
100
 
96
101
  feature_candidates = self.feature_index.get(item_id_str, [])
97
- if require_feature_index and not feature_candidates:
102
+ if strict_feature_index and not feature_candidates:
98
103
  raise ValueError(
99
104
  f"Missing feature index entry for sample id '{item_id_str}'. "
100
105
  "Provide DATA.common.feature_index mapping with feature_paths or feature_dir/path."
@@ -136,6 +141,43 @@ class VQADataset(Dataset):
136
141
  "Expected video_path, frame_paths, or video_frames."
137
142
  )
138
143
 
144
+ def _load_feature_index(
145
+ self,
146
+ feature_index_path: str,
147
+ *,
148
+ split: str,
149
+ strict: bool,
150
+ allow_missing: bool,
151
+ ) -> dict[str, list[str]]:
152
+ if not feature_index_path:
153
+ return {}
154
+
155
+ resolved_path = os.path.abspath(os.path.expanduser(feature_index_path))
156
+ if allow_missing and not os.path.exists(resolved_path):
157
+ logger.warning(
158
+ "VQA feature index unavailable; falling back to raw-video extraction | "
159
+ "feature_source=%s | split=%s | feature_index=%s",
160
+ self.feature_source,
161
+ split,
162
+ resolved_path,
163
+ )
164
+ return {}
165
+
166
+ try:
167
+ return load_feature_index(resolved_path, split=split)
168
+ except Exception:
169
+ if strict or not allow_missing:
170
+ raise
171
+ logger.warning(
172
+ "VQA feature index unreadable; falling back to raw-video extraction | "
173
+ "feature_source=%s | split=%s | feature_index=%s",
174
+ self.feature_source,
175
+ split,
176
+ resolved_path,
177
+ exc_info=True,
178
+ )
179
+ return {}
180
+
139
181
  def __len__(self) -> int:
140
182
  return len(self.samples)
141
183
 
@@ -482,7 +482,7 @@ class QwenXVarsModel(nn.Module):
482
482
  self.raw_extractor = XVarsStrictRawVideoFeatureExtractor(
483
483
  weights_path=self.vision_weights_path,
484
484
  vision_tower=self.vision_tower_name,
485
- prefer_cuda=get_hf_prefer_cuda(config, hf_cfg),
485
+ prefer_cuda=get_hf_prefer_cuda(self.config, hf_cfg),
486
486
  start_frame=self.strict_sampling_cfg.get("start_frame"),
487
487
  end_frame=self.strict_sampling_cfg.get("end_frame"),
488
488
  input_fps=self.strict_sampling_cfg.get("input_fps"),
@@ -492,7 +492,7 @@ class QwenXVarsModel(nn.Module):
492
492
  else:
493
493
  self.raw_extractor = XVarsRawVideoFeatureExtractor(
494
494
  vision_tower=self.vision_tower_name,
495
- prefer_cuda=get_hf_prefer_cuda(config, hf_cfg),
495
+ prefer_cuda=get_hf_prefer_cuda(self.config, hf_cfg),
496
496
  )
497
497
  if isinstance(self.raw_extractor, XVarsStrictRawVideoFeatureExtractor):
498
498
  features, classifier_prior = self.raw_extractor.extract_with_prior(video_path)