diff --git a/.gitignore b/.gitignore index b208eee..860df15 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ outputs/ .idea/ .cursor/ *.mp4 +*secret* # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/configs/motrack/dancetrack/algorithm/tdlp.yaml b/configs/motrack/dancetrack/algorithm/tdlp.yaml new file mode 100644 index 0000000..de6699a --- /dev/null +++ b/configs/motrack/dancetrack/algorithm/tdlp.yaml @@ -0,0 +1,55 @@ +name: tdlp +params: + # --- Fixed (infrastructure) — NOT in search space --- + checkpoint: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108b-fromExp107-BboxEmbDim512/checkpoints/last.pt + architecture: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 512 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + aggregator_type: sum + aggregator_params: {} + device: cuda:0 + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: [0.5, 0.5, 0.5, 0.5, 0.5] + coord_std: + bbox: [0.1, 0.1, 0.1, 0.1, 1.0] + fod_mean: + bbox: [0.0, 0.0, 0.0, 0.0, 0.0] + fod_std: + bbox: [0.05, 0.05, 0.05, 0.05, 1.0] + fod_time_scaled: true + + # --- Tracker hyperparams (defaults from exp108b; optimizer overrides) --- + detection_threshold: 0.4 + sim_threshold: 0.95 + initialization_threshold: 1 + remember_threshold: 50 # also acts as the model's temporal window + new_tracklet_detection_threshold: 0.9 + use_conf: true diff --git a/configs/motrack/dancetrack/dataset/dancetrack.yaml b/configs/motrack/dancetrack/dataset/dancetrack.yaml new file mode 100644 index 0000000..d22bc86 --- /dev/null +++ b/configs/motrack/dancetrack/dataset/dancetrack.yaml @@ -0,0 +1,7 @@ +type: tdlp_dancetrack # resolved via TDLP's DATASET_CATALOG.register +path: DanceTrack-orig # appended to path.assets → /media/home/DanceTrack-orig +params: + index_params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null diff --git a/configs/motrack/dancetrack/eval/default.yaml b/configs/motrack/dancetrack/eval/default.yaml new file mode 100644 index 0000000..6919f2c --- /dev/null +++ b/configs/motrack/dancetrack/eval/default.yaml @@ -0,0 +1,3 @@ +eval_output: online +eval_classes: [1] +distractor_classes: [2, 7, 8, 12] diff --git a/configs/motrack/dancetrack/inference/val.yaml b/configs/motrack/dancetrack/inference/val.yaml new file mode 100644 index 0000000..92d3d59 --- /dev/null +++ b/configs/motrack/dancetrack/inference/val.yaml @@ -0,0 +1,5 @@ +split: val +postprocess: false +override: false +load_image: false +clip: true diff --git a/configs/motrack/dancetrack/object_detection/yolox_cached.yaml b/configs/motrack/dancetrack/object_detection/yolox_cached.yaml new file mode 100644 index 0000000..5f1c38a --- /dev/null +++ b/configs/motrack/dancetrack/object_detection/yolox_cached.yaml @@ -0,0 +1,13 @@ +type: 'mmdet_yolox' +params: + accelerator: cuda:0 + conf: 0.6 # matches history/DanceTrack/tdlp_bboxes_mmdet.yaml + min_bbox_area: 100 + # mmdetection config matching ByteTrack YOLOX-X architecture + model_config: /work/configs/od/mmdet/yolox_x_bytetrack.py + # Model source: https://github.com/ifzhang/ByteTrack, ByteTrack_ablation + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + bytetrack_compat: true +lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json +oracle: false +cache_path: '/workspace/motrack/dancetrack_mmdet_yolox' # populated by tools/inference.py earlier diff --git a/configs/motrack/dancetrack/optimize_base.yaml b/configs/motrack/dancetrack/optimize_base.yaml new file mode 100644 index 0000000..294f75a --- /dev/null +++ b/configs/motrack/dancetrack/optimize_base.yaml @@ -0,0 +1,7 @@ +optimizer: + n_trials: 100 + sampler: tpe + sampler_params: + gamma: 0.2 + direction: maximize + study_name: dancetrack_tdlp_tpe diff --git a/configs/motrack/dancetrack/path/default.yaml b/configs/motrack/dancetrack/path/default.yaml new file mode 100644 index 0000000..f80147b --- /dev/null +++ b/configs/motrack/dancetrack/path/default.yaml @@ -0,0 +1,2 @@ +master: /media/home/MOT-JEPA-outputs/experiments +assets: /media/home diff --git a/configs/motrack/dancetrack/postprocess/dancetrack.yaml b/configs/motrack/dancetrack/postprocess/dancetrack.yaml new file mode 100644 index 0000000..b1828d2 --- /dev/null +++ b/configs/motrack/dancetrack/postprocess/dancetrack.yaml @@ -0,0 +1,4 @@ +init_threshold: 1 +linear_interpolation_threshold: 30 +linear_interpolation_min_tracklet_length: 30 +min_tracklet_length: 0 diff --git a/configs/motrack/dancetrack/tdlp_infer.yaml b/configs/motrack/dancetrack/tdlp_infer.yaml new file mode 100644 index 0000000..5f7a475 --- /dev/null +++ b/configs/motrack/dancetrack/tdlp_infer.yaml @@ -0,0 +1,16 @@ +defaults: + - global_config + - dataset: dancetrack + - inference: val + - eval: default + - object_detection: yolox_cached + - algorithm: tdlp + - postprocess: dancetrack + - path: default + - _self_ + +experiment: 'tdlp-inference' + +mlflow: + enabled: true + tracking_uri: ${oc.env:MLFLOW_TRACKING_URI} diff --git a/configs/motrack/dancetrack/tpe_tdlp.yaml b/configs/motrack/dancetrack/tpe_tdlp.yaml new file mode 100644 index 0000000..62a68c5 --- /dev/null +++ b/configs/motrack/dancetrack/tpe_tdlp.yaml @@ -0,0 +1,41 @@ +defaults: + - global_config + - dataset: dancetrack + - inference: val + - eval: default + - object_detection: yolox_cached + - algorithm: tdlp + - postprocess: dancetrack + - path: default + - optimize_base + - _self_ + +experiment: 'tdlp-tpe' + +mlflow: + enabled: true + tracking_uri: ${oc.env:MLFLOW_TRACKING_URI} + +optimizer: + search_space: + algorithm.params.detection_threshold: + type: float + low: 0.1 + high: 0.9 + algorithm.params.sim_threshold: + type: float + low: 0.1 + high: 0.9 + algorithm.params.initialization_threshold: + type: int + low: 0 + high: 5 + algorithm.params.remember_threshold: + type: int + low: 1 + high: 50 # capped at the model's trained clip_length + algorithm.params.new_tracklet_detection_threshold: + type: float + low: 0.3 + high: 0.9 + min_param: algorithm.params.detection_threshold diff --git a/configs/tdlp_v2/dataset/augmentations/e2e.yaml b/configs/tdlp_v2/dataset/augmentations/e2e.yaml new file mode 100644 index 0000000..72bd8fb --- /dev/null +++ b/configs/tdlp_v2/dataset/augmentations/e2e.yaml @@ -0,0 +1,18 @@ +_target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation +augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.40 + unobs_noise: True + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.10 + proba: 0.10 + unobs_noise: True + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: True + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 diff --git a/configs/tdlp_v2/exp05.yaml b/configs/tdlp_v2/exp05.yaml new file mode 100644 index 0000000..f33698d --- /dev/null +++ b/configs/tdlp_v2/exp05.yaml @@ -0,0 +1,11 @@ +defaults: + - the_global_config + - resources: default.yaml + - dataset: dancetrack.yaml + - train: bce.yaml + - eval: default.yaml + - model_config: mm_tdsp_bboxes_mid.yaml + - path: default.yaml + +experiment_name: exp05_fromExp04_HiddenDim256 +dataset_name: DanceTrack diff --git a/configs/tdlp_v2/model_config/mm_tdsp_bboxes_mid.yaml b/configs/tdlp_v2/model_config/mm_tdsp_bboxes_mid.yaml new file mode 100644 index 0000000..3ff3723 --- /dev/null +++ b/configs/tdlp_v2/model_config/mm_tdsp_bboxes_mid.yaml @@ -0,0 +1,30 @@ +_target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model +mm_dim: 512 +similarity_prediction_head_hidden_dim: 256 +similarity_head_type: mlp + +sph_common_params: + hidden_dim: 256 +sph_per_feature_params: + bbox: + hidden_dim: 256 + +common_params: + hidden_dim: 256 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 2 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 256 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 2 + interaction_encoder_ffn_dim: 1024 +per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + +aggregator_type: sum +aggregator_params: {} diff --git a/configs/tdlp_v2/train/e2e_bce.yaml b/configs/tdlp_v2/train/e2e_bce.yaml new file mode 100644 index 0000000..4797ec3 --- /dev/null +++ b/configs/tdlp_v2/train/e2e_bce.yaml @@ -0,0 +1,8 @@ +defaults: + - bce.yaml + - _self_ + +trainer_type: end_to_end +trainer_params: + n_gradient_frames: 3 + sim_threshold: 0.5 diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 34e412b..f8fccb5 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -1,5 +1,12 @@ # Check docker/Dockerfile version: "3.9" + +networks: + # Owned by the Motrack project's compose; declared external so we attach, + # never create or destroy. Hosts motrack-mlflow / motrack-env. + motrack-net: + external: true + services: tdlp-env: container_name: ${TRAIN_CONT_NAME:-tdlp-env} @@ -21,9 +28,16 @@ services: capabilities: [ gpu ] cpus: '${CPUS:-1.0}' + environment: + - MLFLOW_TRACKING_URI=${MLFLOW_TRACKING_URI} + + networks: + - motrack-net # share network with motrack-mlflow / motrack-env + volumes: - '/tmp:/tmp' - '${DATA}:/media/home' + - '/mnt/data:/mnt/data' - '${CODE:-$PWD}:/work' - '${CLAUDE_CONFIG:-~/.claude}:/root/.claude' diff --git a/history/DanceTrack/ablations/tdlp_AggAttn.yaml b/history/DanceTrack/ablations/tdlp_AggAttn.yaml new file mode 100644 index 0000000..e78e840 --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_AggAttn.yaml @@ -0,0 +1,215 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp111-AggAttn +dataset_name: DanceTrack +resources: + batch_size: 8 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + - keypoints + - appearance + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 10 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 1.0e-05 + weight_decay: 0.001 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 1 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: false + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 1024 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + keypoints: + hidden_dim: 512 + appearance: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + keypoints: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 35 + appearance: + hidden_dim: 512 + feature_encoder_type: parts_appearance + feature_encoder_params: + emb_size: 128 + hidden_dim: 512 + track_encoder_enable_motion_encoder: false + track_encoder_ffn_dim: 1024 + interaction_encoder_ffn_dim: 1024 + aggregator_type: attn + aggregator_params: + hidden_dim: ${model_config.mm_dim} + per_feature_checkpoint: + bbox: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108b-fromExp107-BboxEmbDim512/checkpoints/last.pt + keypoints: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108k-fromExp107-BboxEmbDim512/checkpoints/last.pt + appearance: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp107a-fromExp105-ScaleUp/checkpoints/last.pt + object_interaction_encoder_enable: true + object_interaction_encoder_params: + hidden_dim: ${model_config.mm_dim} + n_heads: 8 + n_layers: 2 + dropout: 0.1 +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.985 + initialization_threshold: 3 + new_tracklet_detection_threshold: 0.9 + split: val + checkpoint: null + visualize: false + postprocess_enable: false +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_AggConcat.yaml b/history/DanceTrack/ablations/tdlp_AggConcat.yaml new file mode 100644 index 0000000..47c1356 --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_AggConcat.yaml @@ -0,0 +1,215 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp111-AggConcat +dataset_name: DanceTrack +resources: + batch_size: 8 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + - keypoints + - appearance + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 10 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 1.0e-05 + weight_decay: 0.001 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 1 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: false + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 1024 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + keypoints: + hidden_dim: 512 + appearance: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + keypoints: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 35 + appearance: + hidden_dim: 512 + feature_encoder_type: parts_appearance + feature_encoder_params: + emb_size: 128 + hidden_dim: 512 + track_encoder_enable_motion_encoder: false + track_encoder_ffn_dim: 1024 + interaction_encoder_ffn_dim: 1024 + aggregator_type: concat_mlp + aggregator_params: + hidden_dim: ${model_config.mm_dim} + per_feature_checkpoint: + bbox: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108b-fromExp107-BboxEmbDim512/checkpoints/last.pt + keypoints: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108k-fromExp107-BboxEmbDim512/checkpoints/last.pt + appearance: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp107a-fromExp105-ScaleUp/checkpoints/last.pt + object_interaction_encoder_enable: true + object_interaction_encoder_params: + hidden_dim: ${model_config.mm_dim} + n_heads: 8 + n_layers: 2 + dropout: 0.1 +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.985 + initialization_threshold: 3 + new_tracklet_detection_threshold: 0.9 + split: val + checkpoint: null + visualize: false + postprocess_enable: false +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_AggLinearSum.yaml b/history/DanceTrack/ablations/tdlp_AggLinearSum.yaml new file mode 100644 index 0000000..469d4cf --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_AggLinearSum.yaml @@ -0,0 +1,215 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp111-AggLinearSum +dataset_name: DanceTrack +resources: + batch_size: 8 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + - keypoints + - appearance + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 10 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 1.0e-05 + weight_decay: 0.001 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 1 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: false + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 1024 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + keypoints: + hidden_dim: 512 + appearance: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + keypoints: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 35 + appearance: + hidden_dim: 512 + feature_encoder_type: parts_appearance + feature_encoder_params: + emb_size: 128 + hidden_dim: 512 + track_encoder_enable_motion_encoder: false + track_encoder_ffn_dim: 1024 + interaction_encoder_ffn_dim: 1024 + aggregator_type: linear_sum + aggregator_params: + hidden_dim: ${model_config.mm_dim} + per_feature_checkpoint: + bbox: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108b-fromExp107-BboxEmbDim512/checkpoints/last.pt + keypoints: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108k-fromExp107-BboxEmbDim512/checkpoints/last.pt + appearance: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp107a-fromExp105-ScaleUp/checkpoints/last.pt + object_interaction_encoder_enable: true + object_interaction_encoder_params: + hidden_dim: ${model_config.mm_dim} + n_heads: 8 + n_layers: 2 + dropout: 0.1 +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.985 + initialization_threshold: 3 + new_tracklet_detection_threshold: 0.9 + split: val + checkpoint: null + visualize: false + postprocess_enable: false +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_AggLinearSumRerun.yaml b/history/DanceTrack/ablations/tdlp_AggLinearSumRerun.yaml new file mode 100644 index 0000000..0f59506 --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_AggLinearSumRerun.yaml @@ -0,0 +1,215 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp111-AggLinearSumRerun +dataset_name: DanceTrack +resources: + batch_size: 8 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + - keypoints + - appearance + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 10 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 1.0e-05 + weight_decay: 0.001 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 1 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: false + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 1024 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + keypoints: + hidden_dim: 512 + appearance: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + keypoints: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 35 + appearance: + hidden_dim: 512 + feature_encoder_type: parts_appearance + feature_encoder_params: + emb_size: 128 + hidden_dim: 512 + track_encoder_enable_motion_encoder: false + track_encoder_ffn_dim: 1024 + interaction_encoder_ffn_dim: 1024 + aggregator_type: linear_sum + aggregator_params: + hidden_dim: ${model_config.mm_dim} + per_feature_checkpoint: + bbox: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108b-fromExp107-BboxEmbDim512/checkpoints/last.pt + keypoints: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108k-fromExp107-BboxEmbDim512/checkpoints/last.pt + appearance: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp107a-fromExp105-ScaleUp/checkpoints/last.pt + object_interaction_encoder_enable: true + object_interaction_encoder_params: + hidden_dim: ${model_config.mm_dim} + n_heads: 8 + n_layers: 2 + dropout: 0.1 +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.985 + initialization_threshold: 3 + new_tracklet_detection_threshold: 0.9 + split: val + checkpoint: null + visualize: false + postprocess_enable: false +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack diff --git a/history/DanceTrack/ablations/tdlp_AggQuery.yaml b/history/DanceTrack/ablations/tdlp_AggQuery.yaml new file mode 100644 index 0000000..eb40a01 --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_AggQuery.yaml @@ -0,0 +1,215 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp111-AggQuery +dataset_name: DanceTrack +resources: + batch_size: 8 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + - keypoints + - appearance + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 10 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 1.0e-05 + weight_decay: 0.001 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 1 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: false + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 1024 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + keypoints: + hidden_dim: 512 + appearance: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + keypoints: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 35 + appearance: + hidden_dim: 512 + feature_encoder_type: parts_appearance + feature_encoder_params: + emb_size: 128 + hidden_dim: 512 + track_encoder_enable_motion_encoder: false + track_encoder_ffn_dim: 1024 + interaction_encoder_ffn_dim: 1024 + aggregator_type: query + aggregator_params: + hidden_dim: ${model_config.mm_dim} + per_feature_checkpoint: + bbox: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108b-fromExp107-BboxEmbDim512/checkpoints/last.pt + keypoints: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108k-fromExp107-BboxEmbDim512/checkpoints/last.pt + appearance: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp107a-fromExp105-ScaleUp/checkpoints/last.pt + object_interaction_encoder_enable: true + object_interaction_encoder_params: + hidden_dim: ${model_config.mm_dim} + n_heads: 8 + n_layers: 2 + dropout: 0.1 +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.985 + initialization_threshold: 3 + new_tracklet_detection_threshold: 0.9 + split: val + checkpoint: null + visualize: false + postprocess_enable: false +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_FullNoInter.yaml b/history/DanceTrack/ablations/tdlp_FullNoInter.yaml new file mode 100644 index 0000000..d94cdc2 --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_FullNoInter.yaml @@ -0,0 +1,214 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp111-FullNoInter +dataset_name: DanceTrack +resources: + batch_size: 8 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + - keypoints + - appearance + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 10 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 1.0e-05 + weight_decay: 0.001 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 1 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: false + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 1024 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + keypoints: + hidden_dim: 512 + appearance: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: false + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + keypoints: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 35 + appearance: + hidden_dim: 512 + feature_encoder_type: parts_appearance + feature_encoder_params: + emb_size: 128 + hidden_dim: 512 + track_encoder_enable_motion_encoder: false + track_encoder_ffn_dim: 1024 + interaction_encoder_ffn_dim: 1024 + aggregator_type: sum + aggregator_params: {} + per_feature_checkpoint: + bbox: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108b-NoInter/checkpoints/last.pt + keypoints: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108k-NoInter/checkpoints/last.pt + appearance: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp107a-NoInter/checkpoints/last.pt + object_interaction_encoder_enable: false + object_interaction_encoder_params: + hidden_dim: ${model_config.mm_dim} + n_heads: 8 + n_layers: 2 + dropout: 0.1 +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.985 + initialization_threshold: 3 + new_tracklet_detection_threshold: 0.9 + split: val + checkpoint: null + visualize: false + postprocess_enable: false +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_MMOnlyInter.yaml b/history/DanceTrack/ablations/tdlp_MMOnlyInter.yaml new file mode 100644 index 0000000..5022f7e --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_MMOnlyInter.yaml @@ -0,0 +1,214 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp111-MMOnlyInter +dataset_name: DanceTrack +resources: + batch_size: 8 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + - keypoints + - appearance + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 10 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 1.0e-05 + weight_decay: 0.001 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 1 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: false + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 1024 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + keypoints: + hidden_dim: 512 + appearance: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: false + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + keypoints: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 35 + appearance: + hidden_dim: 512 + feature_encoder_type: parts_appearance + feature_encoder_params: + emb_size: 128 + hidden_dim: 512 + track_encoder_enable_motion_encoder: false + track_encoder_ffn_dim: 1024 + interaction_encoder_ffn_dim: 1024 + aggregator_type: sum + aggregator_params: {} + per_feature_checkpoint: + bbox: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108b-NoInter/checkpoints/last.pt + keypoints: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108k-NoInter/checkpoints/last.pt + appearance: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp107a-NoInter/checkpoints/last.pt + object_interaction_encoder_enable: true + object_interaction_encoder_params: + hidden_dim: ${model_config.mm_dim} + n_heads: 8 + n_layers: 2 + dropout: 0.1 +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.985 + initialization_threshold: 3 + new_tracklet_detection_threshold: 0.9 + split: val + checkpoint: null + visualize: false + postprocess_enable: false +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_NoInter.yaml b/history/DanceTrack/ablations/tdlp_NoInter.yaml new file mode 100644 index 0000000..ebf515a --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_NoInter.yaml @@ -0,0 +1,214 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp111-NoInter +dataset_name: DanceTrack +resources: + batch_size: 8 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + - keypoints + - appearance + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 10 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 1.0e-05 + weight_decay: 0.001 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 1 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: false + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 1024 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + keypoints: + hidden_dim: 512 + appearance: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + keypoints: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 35 + appearance: + hidden_dim: 512 + feature_encoder_type: parts_appearance + feature_encoder_params: + emb_size: 128 + hidden_dim: 512 + track_encoder_enable_motion_encoder: false + track_encoder_ffn_dim: 1024 + interaction_encoder_ffn_dim: 1024 + aggregator_type: sum + aggregator_params: {} + per_feature_checkpoint: + bbox: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108b-fromExp107-BboxEmbDim512/checkpoints/last.pt + keypoints: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp108k-fromExp107-BboxEmbDim512/checkpoints/last.pt + appearance: /media/home/MOT-JEPA-outputs/experiments/DanceTrack/exp107a-fromExp105-ScaleUp/checkpoints/last.pt + object_interaction_encoder_enable: false + object_interaction_encoder_params: + hidden_dim: ${model_config.mm_dim} + n_heads: 8 + n_layers: 2 + dropout: 0.1 +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.985 + initialization_threshold: 3 + new_tracklet_detection_threshold: 0.9 + split: val + checkpoint: null + visualize: false + postprocess_enable: false +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_appearance_NoInter.yaml b/history/DanceTrack/ablations/tdlp_appearance_NoInter.yaml new file mode 100644 index 0000000..715f4f0 --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_appearance_NoInter.yaml @@ -0,0 +1,188 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp107a-NoInter +dataset_name: DanceTrack +resources: + batch_size: 32 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - appearance + random_appearance_jitter_ratio: 0.0 + random_appearance_jitter_range: 0 + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 20 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 5.0e-05 + weight_decay: 0.01 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 2 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: true + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 512 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + appearance: + hidden_dim: 512 + common_params: + hidden_dim: 256 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 512 + projector_intermediate_dim: 512 + interaction_encoder_enable: false + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 512 + per_feature_params: + appearance: + hidden_dim: 512 + feature_encoder_type: parts_appearance + feature_encoder_params: + emb_size: 128 + hidden_dim: 512 + track_encoder_enable_motion_encoder: false + track_encoder_ffn_dim: 1024 + interaction_encoder_ffn_dim: 1024 + aggregator_type: sum + aggregator_params: {} +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.90 + initialization_threshold: 1 + new_tracklet_detection_threshold: 0.9 + split: val + checkpoint: null + visualize: false + postprocess_enable: true +analysis: null diff --git a/history/DanceTrack/ablations/tdlp_bboxes_HeadConcat.yaml b/history/DanceTrack/ablations/tdlp_bboxes_HeadConcat.yaml new file mode 100644 index 0000000..8736e1a --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_bboxes_HeadConcat.yaml @@ -0,0 +1,190 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp108b-HeadConcat +dataset_name: DanceTrack +resources: + batch_size: 16 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 20 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 5.0e-05 + weight_decay: 0.01 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 2 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: true + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 512 + similarity_head_type: concat_mlp + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + aggregator_type: sum + aggregator_params: {} +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.95 + initialization_threshold: 1 + new_tracklet_detection_threshold: 0.9 + demo: + video_path: /work/input.mp4 + output_path: /work/output.mp4 + fps: 25 + split: val + checkpoint: null + visualize: false + postprocess_enable: true +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack_bboxes \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_bboxes_HeadDiff.yaml b/history/DanceTrack/ablations/tdlp_bboxes_HeadDiff.yaml new file mode 100644 index 0000000..805e75f --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_bboxes_HeadDiff.yaml @@ -0,0 +1,190 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp108b-HeadDiff +dataset_name: DanceTrack +resources: + batch_size: 16 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 20 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 5.0e-05 + weight_decay: 0.01 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 2 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: true + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 512 + similarity_head_type: compact_mlp + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + aggregator_type: sum + aggregator_params: {} +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.95 + initialization_threshold: 1 + new_tracklet_detection_threshold: 0.9 + demo: + video_path: /work/input.mp4 + output_path: /work/output.mp4 + fps: 25 + split: val + checkpoint: null + visualize: false + postprocess_enable: true +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack_bboxes \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_bboxes_HeadDot.yaml b/history/DanceTrack/ablations/tdlp_bboxes_HeadDot.yaml new file mode 100644 index 0000000..5361728 --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_bboxes_HeadDot.yaml @@ -0,0 +1,190 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp108b-HeadDot +dataset_name: DanceTrack +resources: + batch_size: 16 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 20 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 5.0e-05 + weight_decay: 0.01 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 2 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: true + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 512 + similarity_head_type: dot_product + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + aggregator_type: sum + aggregator_params: {} +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.95 + initialization_threshold: 1 + new_tracklet_detection_threshold: 0.9 + demo: + video_path: /work/input.mp4 + output_path: /work/output.mp4 + fps: 25 + split: val + checkpoint: null + visualize: false + postprocess_enable: true +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack_bboxes \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_bboxes_NoInter.yaml b/history/DanceTrack/ablations/tdlp_bboxes_NoInter.yaml new file mode 100644 index 0000000..3d0f878 --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_bboxes_NoInter.yaml @@ -0,0 +1,189 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp108b-NoInter +dataset_name: DanceTrack +resources: + batch_size: 16 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 20 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 5.0e-05 + weight_decay: 0.01 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 2 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: true + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 512 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: false + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + aggregator_type: sum + aggregator_params: {} +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.95 + initialization_threshold: 1 + new_tracklet_detection_threshold: 0.9 + demo: + video_path: /work/input.mp4 + output_path: /work/output.mp4 + fps: 25 + split: val + checkpoint: null + visualize: false + postprocess_enable: true +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack_bboxes \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_bboxes_PosWeight1.yaml b/history/DanceTrack/ablations/tdlp_bboxes_PosWeight1.yaml new file mode 100644 index 0000000..4f93351 --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_bboxes_PosWeight1.yaml @@ -0,0 +1,189 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp108b-PosWeight1 +dataset_name: DanceTrack +resources: + batch_size: 16 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 20 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 1.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 5.0e-05 + weight_decay: 0.01 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 2 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: true + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 512 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + aggregator_type: sum + aggregator_params: {} +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.95 + initialization_threshold: 1 + new_tracklet_detection_threshold: 0.9 + demo: + video_path: /work/input.mp4 + output_path: /work/output.mp4 + fps: 25 + split: val + checkpoint: null + visualize: false + postprocess_enable: true +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack_bboxes \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_bboxes_PosWeight100.yaml b/history/DanceTrack/ablations/tdlp_bboxes_PosWeight100.yaml new file mode 100644 index 0000000..9605192 --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_bboxes_PosWeight100.yaml @@ -0,0 +1,189 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp108b-PosWeight100 +dataset_name: DanceTrack +resources: + batch_size: 16 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 20 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 100.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 5.0e-05 + weight_decay: 0.01 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 2 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: true + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 512 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + aggregator_type: sum + aggregator_params: {} +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.95 + initialization_threshold: 1 + new_tracklet_detection_threshold: 0.9 + demo: + video_path: /work/input.mp4 + output_path: /work/output.mp4 + fps: 25 + split: val + checkpoint: null + visualize: false + postprocess_enable: true +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack_bboxes \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_bboxes_PosWeight20.yaml b/history/DanceTrack/ablations/tdlp_bboxes_PosWeight20.yaml new file mode 100644 index 0000000..23d2c18 --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_bboxes_PosWeight20.yaml @@ -0,0 +1,189 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp108b-PosWeight20 +dataset_name: DanceTrack +resources: + batch_size: 16 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 16 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - bbox + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 20 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 20.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 5.0e-05 + weight_decay: 0.01 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 2 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: true + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 512 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + bbox: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: true + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + bbox: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 5 + aggregator_type: sum + aggregator_params: {} +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + tracker: + remember_threshold: 50 + detection_threshold: 0.4 + sim_threshold: 0.95 + initialization_threshold: 1 + new_tracklet_detection_threshold: 0.9 + demo: + video_path: /work/input.mp4 + output_path: /work/output.mp4 + fps: 25 + split: val + checkpoint: null + visualize: false + postprocess_enable: true +analysis: null + +hf: + username: Robotmurlock + model_name: tdlp_dancetrack_bboxes \ No newline at end of file diff --git a/history/DanceTrack/ablations/tdlp_keypoints_NoInter.yaml b/history/DanceTrack/ablations/tdlp_keypoints_NoInter.yaml new file mode 100644 index 0000000..f96dd07 --- /dev/null +++ b/history/DanceTrack/ablations/tdlp_keypoints_NoInter.yaml @@ -0,0 +1,175 @@ +defaults: + - the_global_config + - _self_ + +experiment_name: exp108k-NoInter +dataset_name: DanceTrack +resources: + batch_size: 16 + accelerator: cuda:0 + num_workers: 20 + val_batch_size: 8 +dataset: + index: + type: mot + params: + paths: + - /media/home/DanceTrack-orig/ + sequence_list: null + n_tracks: 40 + clip_length: 50 + min_clip_tracks: 1 + clip_sampling_step: 1 + val_clip_sampling_step: 1 + feature_extractor: + extractor_type: pred_bbox + extractor_params: + prediction_path: /media/home/cameltrack-states/extracted-features + extra_false_positives: true + feature_names: + - keypoints + transform: + _target_: tdlp.datasets.dataset.transform.ComposeTransform + transforms: + - _target_: tdlp.datasets.dataset.transform.BBoxXYWHtoXYXY + - _target_: tdlp.datasets.dataset.transform.BBoxMinMaxScaling + - _target_: tdlp.datasets.dataset.transform.FeatureFODStandardization + coord_mean: + bbox: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + keypoints: + - - 35 + - - 0.5 + coord_std: + bbox: + - 0.1 + - 0.1 + - 0.1 + - 0.1 + - 1.0 + keypoints: + - - 17 + - - 0.1 + - 0.1 + - 1.0 + fod_mean: + bbox: + - 0.0 + - 0.0 + - 0.0 + - 0.0 + - 0.0 + keypoints: + - - 35 + - - 0.0 + fod_std: + bbox: + - 0.05 + - 0.05 + - 0.05 + - 0.05 + - 1.0 + keypoints: + - - 17 + - - 0.05 + - 0.05 + - 1.0 + fod_time_scaled: true + augmentations: + _target_: tdlp.datasets.dataset.augmentations.base.CompositionAugmentation + augmentations: + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.05 + proba: 0.4 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.1 + proba: 0.1 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.bbox.BBoxGaussianNoiseAugmentation + sigma: 0.25 + proba: 0.05 + unobs_noise: true + - _target_: tdlp.datasets.dataset.augmentations.video.PointOcclusionAugmentations + drop_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.video.LeftOrRightOcclusionAugmentations + drop_ratio: 0.2 + - _target_: tdlp.datasets.dataset.augmentations.video.IdentitySwitchAugmentation + switch_ratio: 0.3 + - _target_: tdlp.datasets.dataset.augmentations.appearance.AppearanceNoiseAugmentation + alpha: 0.4 + - _target_: tdlp.datasets.dataset.augmentations.video.SmartIdentitySwitchAugmentation + switch_ratio: 0.5 + iou_threshold: 0.5 + max_switch_ratio: 0.5 + sampler: null + use_batch_sampler: false +train: + max_epochs: 20 + loss_config: + _target_: tdlp.trainer.losses.bce.ClipLevelBCE + pos_weight: 10.0 + assoc_threshold: 0.01 + optimizer_config: + _target_: torch.optim.AdamW + lr: 5.0e-05 + weight_decay: 0.01 + scheduler_config: + _target_: tdlp.trainer.scheduler.create_warmup_cosine_annealing_scheduler + n_warmup_epochs: 2 + gradient_clip: 1.0 + mixed_precision: true + resume: false + truncate: false + checkpoint_cfg: + metric_monitor: val-epoch/loss + resume_from: null +model_config: + _target_: tdlp.architectures.tdlp.core.build_mm_tdsp_model + mm_dim: 1024 + similarity_prediction_head_hidden_dim: 512 + sph_common_params: + hidden_dim: 512 + sph_per_feature_params: + keypoints: + hidden_dim: 512 + common_params: + hidden_dim: 512 + dropout: 0.1 + track_encoder_n_heads: 8 + track_encoder_n_layers: 4 + track_encoder_ffn_dim: 1024 + projector_intermediate_dim: 512 + interaction_encoder_enable: false + interaction_encoder_n_heads: 8 + interaction_encoder_n_layers: 4 + interaction_encoder_ffn_dim: 1024 + per_feature_params: + keypoints: + feature_encoder_type: motion + feature_encoder_params: + input_dim: 35 + aggregator_type: sum + aggregator_params: {} +path: + master: /media/home/MOT-JEPA-outputs +eval: + object_detection: + type: yolox + params: + accelerator: cuda:0 + conf: 0.6 + min_bbox_area: 100 + model_path: /media/home/DanceTrack-orig/.other/bytetrack_models/bytetrack_model.pth.tar + lookup_path: /media/home/DanceTrack-orig/.other/.lookup.json + cache_path: /workspace/motrack/dancetrack_yolox + oracle: false + split: val + checkpoint: null + visualize: false + postprocess_enable: true +analysis: null diff --git a/pyproject.toml b/pyproject.toml index c82ce40..934a911 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ dependencies = [ "matplotlib>=3.10.3", "mmdet>=3.3.0", "mmengine>=0.10.0", - "motrack>=0.6.0", + "motrack[mlflow]==0.7.0", "numpy>=1.24.0,<2.0", "omegaconf>=2.3.0", "opencv-python>=4.11.0.86", diff --git a/tdlp/architectures/tdlp/aggregators.py b/tdlp/architectures/tdlp/aggregators.py index ca24353..3d30035 100644 --- a/tdlp/architectures/tdlp/aggregators.py +++ b/tdlp/architectures/tdlp/aggregators.py @@ -1,7 +1,7 @@ """Aggregation layers for TDCP models.""" from __future__ import annotations from abc import ABC, abstractmethod -from typing import Any, Dict, Sequence +from typing import Any, Dict, Optional, Sequence import einops import torch @@ -149,9 +149,34 @@ def forward(self, features: Sequence[torch.Tensor]) -> torch.Tensor: +class TDCPConcatMLPAggregator(TDCPAggregator): + """Concatenation followed by an MLP — symmetric counterpart of `linear_sum`. + + Concatenates all per-modality embeddings, then projects through a + bottleneck MLP back to `hidden_dim`. Captures cross-modal interactions + inside the MLP weights rather than via per-modality projections. + """ + def __init__(self, n_features: int, hidden_dim: int, intermediate_dim: Optional[int] = None): + super().__init__(n_features) + self._hidden_dim = hidden_dim + intermediate_dim = intermediate_dim or hidden_dim + self.mlp = nn.Sequential( + nn.Linear(n_features * hidden_dim, intermediate_dim), + nn.LayerNorm(intermediate_dim), + nn.SiLU(), + nn.Linear(intermediate_dim, hidden_dim), + ) + + def forward(self, features: Sequence[Tensor]) -> Tensor: + assert len(features) == self.n_features + x = torch.cat(list(features), dim=-1) # [B, M*D] + return self.mlp(x) # [B, D] + + TDCP_AGGREGATOR_CATALOG = { 'sum': TDCPSumAggregator, 'linear_sum': TDCPLinearSumAggregator, + 'concat_mlp': TDCPConcatMLPAggregator, 'static_softmax': TDCPStaticSoftmaxSum, 'attn': TDCPAttnWeightedSum, 'query': TDCPQueryAttentionPool, diff --git a/tdlp/architectures/tdlp/base.py b/tdlp/architectures/tdlp/base.py new file mode 100644 index 0000000..32a2bde --- /dev/null +++ b/tdlp/architectures/tdlp/base.py @@ -0,0 +1,61 @@ +"""Abstract base class for all TDLP association models.""" +from abc import ABC, abstractmethod +from typing import Any + +import torch +from torch import nn + + +class TDLPModel(nn.Module, ABC): + """Abstract interface for all TDLP association models. + + All TDLP models (contrastive and similarity-based) must implement: + - forward: run the model on track history and detection features. + - prepare_loss_inputs: bridge model output to loss function signature. + - compute_cost_matrix: convert model output to an association cost matrix. + """ + + @abstractmethod + def prepare_loss_inputs( + self, + model_output: Any, + track_mask: torch.Tensor, + det_mask: torch.Tensor, + track_ids: torch.Tensor, + det_ids: torch.Tensor, + ) -> tuple: + """Convert model output to loss function arguments. + + Returns a tuple that can be unpacked directly into the loss function: + loss_func(*prepare_loss_inputs(...)) + + Args: + model_output: Raw output from self.forward(). + track_mask: (B, N, T) boolean mask. True = missing. + det_mask: (B, N) boolean mask. True = missing. + track_ids: (B, N, T) track identity labels. + det_ids: (B, N) detection identity labels. + + Returns: + Tuple of positional arguments for the loss function. + """ + ... + + @abstractmethod + def compute_cost_matrix( + self, + model_output: Any, + n_tracks: int, + n_dets: int, + ) -> torch.Tensor: + """Compute association cost matrix from model output. + + Args: + model_output: Raw output from self.forward(). + n_tracks: Number of valid tracks (rows in cost matrix). + n_dets: Number of valid detections (columns in cost matrix). + + Returns: + (B, n_tracks, n_dets) cost tensor in [0, 1]. Lower = better match. + """ + ... diff --git a/tdlp/architectures/tdlp/core.py b/tdlp/architectures/tdlp/core.py index 384d597..ef19d2d 100644 --- a/tdlp/architectures/tdlp/core.py +++ b/tdlp/architectures/tdlp/core.py @@ -6,8 +6,10 @@ import torch from torch import nn +from torch.nn import functional as F from tdlp.architectures.tdlp import utils as tdcp_utils +from tdlp.architectures.tdlp.base import TDLPModel from tdlp.architectures.tdlp.aggregators import TDCPAggregator, tdcp_aggregator_factory from tdlp.architectures.tdlp.feature_encoders import feature_encoder_factory from tdlp.architectures.tdlp.object_interaction_encoder import ObjectInteractionEncoder @@ -18,7 +20,7 @@ logger = logging.getLogger('Architecture') -class TrackDetectionContrastivePrediction(nn.Module): +class TrackDetectionContrastivePrediction(TDLPModel): """Contrastive model comparing track and detection embeddings.""" def __init__( @@ -79,8 +81,18 @@ def forward( return projected_features, det_features + def prepare_loss_inputs(self, model_output, track_mask, det_mask, track_ids, det_ids): + track_features, det_features = model_output + return (track_features, det_features, track_mask, det_mask, None, None, track_ids, det_ids) -class MultiModalTDCP(nn.Module): + def compute_cost_matrix(self, model_output, n_tracks, n_dets): + track_feat = F.normalize(model_output[0][:, :n_tracks], dim=-1) + det_feat = F.normalize(model_output[1][:, :n_dets], dim=-1) + sim = torch.bmm(track_feat, det_feat.transpose(1, 2)) + return 1 - (sim + 1) / 2 + + +class MultiModalTDCP(TDLPModel): """Multi-modal TDCP wrapper handling per-feature models and aggregation.""" def __init__( self, @@ -154,8 +166,18 @@ def forward( return agg_track_features, agg_det_features, track_features, det_features + def prepare_loss_inputs(self, model_output, track_mask, det_mask, track_ids, det_ids): + agg_track, agg_det, track_dict, det_dict = model_output + return (agg_track, agg_det, track_mask, det_mask, track_dict, det_dict, track_ids, det_ids) + + def compute_cost_matrix(self, model_output, n_tracks, n_dets): + track_feat = F.normalize(model_output[0][:, :n_tracks], dim=-1) + det_feat = F.normalize(model_output[1][:, :n_dets], dim=-1) + sim = torch.bmm(track_feat, det_feat.transpose(1, 2)) + return 1 - (sim + 1) / 2 -class TrackDetectionSimilarityPrediction(nn.Module): + +class TrackDetectionSimilarityPrediction(TDLPModel): """Similarity model comparing track and detection embeddings.""" def __init__( @@ -183,8 +205,16 @@ def forward( logits = self._similarity_prediction_head(track_features, det_features) return logits + def prepare_loss_inputs(self, model_output, track_mask, det_mask, track_ids, det_ids): + logits = model_output + return (logits, track_mask, det_mask, track_ids, det_ids, None) + + def compute_cost_matrix(self, model_output, n_tracks, n_dets): + logits = model_output + return 1 - torch.sigmoid(logits[:, :n_tracks, :n_dets]) -class MultiModalTDSP(nn.Module): + +class MultiModalTDSP(TDLPModel): """Multi-modal TDSP wrapper handling per-feature models and aggregation.""" def __init__( self, @@ -231,6 +261,15 @@ def forward( return agg_logits, sphs_logits + def prepare_loss_inputs(self, model_output, track_mask, det_mask, track_ids, det_ids): + agg_logits, logits_dict = model_output + return (agg_logits, track_mask, det_mask, track_ids, det_ids, logits_dict) + + def compute_cost_matrix(self, model_output, n_tracks, n_dets): + agg_logits = model_output[0] + return 1 - torch.sigmoid(agg_logits[:, :n_tracks, :n_dets]) + + def build_tdcp_model( feature_encoder_type: str = 'motion', feature_encoder_params: Dict[str, Any] = None, diff --git a/tdlp/architectures/tdlp/similarity_prediction.py b/tdlp/architectures/tdlp/similarity_prediction.py index c07f550..1fa1e74 100644 --- a/tdlp/architectures/tdlp/similarity_prediction.py +++ b/tdlp/architectures/tdlp/similarity_prediction.py @@ -1,4 +1,5 @@ """Similarity prediction heads for TDLP.""" +import math from typing import Optional from torch import nn @@ -145,9 +146,72 @@ def forward( return scores +class TDSPConcatMLPHead(nn.Module): + """MLP head over plain concatenation [z1, z2] — no absolute-difference term.""" + + def __init__( + self, + input_dim: int, + hidden_dim: int, + ): + super().__init__() + self._mlp = nn.Sequential( + nn.Linear(2 * input_dim, hidden_dim), + nn.LayerNorm(hidden_dim), + nn.SiLU(), + nn.Linear(hidden_dim, 1), + ) + + def forward( + self, + track_features: torch.Tensor, + det_features: torch.Tensor, + ) -> torch.Tensor: + track_features = F.normalize(track_features, dim=-1) + det_features = F.normalize(det_features, dim=-1) + B, N, E = track_features.shape + _, M, _ = det_features.shape + t = track_features.unsqueeze(2).expand(B, N, M, E) + d = det_features.unsqueeze(1).expand(B, N, M, E) + pair = torch.cat([t, d], dim=-1) + scores = self._mlp(pair.reshape(B * N * M, 2 * E)).view(B, N, M) + return scores + + +class TDSPDotProductHead(nn.Module): + """Dot-product head: logit = tau * (z_t . z_d) + bias. + + L2-normalized inputs give cosine similarity in [-1, 1]; a learnable temperature + and bias calibrate it for BCE-with-logits. Without calibration the sigmoid + would saturate at ~0.73 for perfect matches. + """ + + def __init__( + self, + input_dim: int, + hidden_dim: Optional[int] = None, # noqa: ARG002 — kept for factory-signature compatibility + init_temperature: float = 4.0, + ): + super().__init__() + self._log_temperature = nn.Parameter(torch.tensor(math.log(init_temperature))) + self._bias = nn.Parameter(torch.zeros(1)) + + def forward( + self, + track_features: torch.Tensor, + det_features: torch.Tensor, + ) -> torch.Tensor: + track_features = F.normalize(track_features, dim=-1) + det_features = F.normalize(det_features, dim=-1) + cos_sim = torch.bmm(track_features, det_features.transpose(1, 2)) + return cos_sim * torch.exp(self._log_temperature) + self._bias + + SIMILARITY_HEAD_CATALOG = { 'mlp': TDSPMLPHead, 'compact_mlp': TDSPCompactMLPHead, + 'concat_mlp': TDSPConcatMLPHead, + 'dot_product': TDSPDotProductHead, } diff --git a/tdlp/common/project.py b/tdlp/common/project.py index 39d7ecc..a0c3ccb 100644 --- a/tdlp/common/project.py +++ b/tdlp/common/project.py @@ -8,3 +8,4 @@ CONFIGS_PATH = os.path.join(ROOT_PATH, 'configs', 'tdlp') OUTPUTS_PATH = os.path.join(ROOT_PATH, 'outputs') PLAYGROUND_PATH = os.path.join(ROOT_PATH, 'playground') +MOTRACK_CONFIGS_PATH = os.path.join(ROOT_PATH, 'configs', 'motrack') diff --git a/tdlp/config_parser/core.py b/tdlp/config_parser/core.py index 0c10a87..a5aff0d 100644 --- a/tdlp/config_parser/core.py +++ b/tdlp/config_parser/core.py @@ -129,6 +129,9 @@ class TrainConfig: optimizer_config: dict scheduler_config: dict + trainer_type: str = 'default' + trainer_params: Optional[dict] = None + gradient_clip: Optional[float] = None mixed_precision: bool = False diff --git a/tdlp/datasets/__init__.py b/tdlp/datasets/__init__.py index e69de29..774fd0d 100644 --- a/tdlp/datasets/__init__.py +++ b/tdlp/datasets/__init__.py @@ -0,0 +1 @@ +from tdlp.datasets.dataset import motrack_register # noqa: F401 — registers 'tdlp_dancetrack' in DATASET_CATALOG diff --git a/tdlp/datasets/dataset/motrack_register.py b/tdlp/datasets/dataset/motrack_register.py new file mode 100644 index 0000000..2ead89f --- /dev/null +++ b/tdlp/datasets/dataset/motrack_register.py @@ -0,0 +1,36 @@ +""" +Registers TDLP's MotrackDatasetWrapper as a regular Motrack dataset type, +so motrack.datasets.dataset_factory('tdlp_dancetrack', ...) works. +""" +from typing import List, Optional + +from motrack.datasets.catalog import DATASET_CATALOG + +from tdlp.datasets.dataset import dataset_index_factory +from tdlp.datasets.dataset.motrack import MotrackDatasetWrapper + + +@DATASET_CATALOG.register('tdlp_dancetrack') +def _build_tdlp_dancetrack( + path: str, # noqa: ARG001 (motrack-derived, ignored: TDLP uses index_params.paths) + test: bool, + index_params: dict, + sequence_list: Optional[List[str]] = None, + split: str = 'val', +): + """Build a TDLP-backed dataset wrapped to look like a Motrack dataset. + + Motrack's ``dataset_factory`` injects ``path`` and ``test`` into ``params`` + and unpacks the whole dict as kwargs. ``path`` is the motrack-derived + fullpath (``//``), but TDLP's MOT index needs + its own ``paths`` list (parent dir, no split suffix), so we ignore ``path`` + and use ``index_params`` from the yaml. + """ + actual_split = 'test' if test else split + dataset_index = dataset_index_factory( + name='mot', + params=index_params, + split=actual_split, + sequence_list=sequence_list, + ) + return MotrackDatasetWrapper(dataset_index) diff --git a/tdlp/object_detection/__init__.py b/tdlp/object_detection/__init__.py index cc47482..a870574 100644 --- a/tdlp/object_detection/__init__.py +++ b/tdlp/object_detection/__init__.py @@ -1,5 +1,7 @@ """ -Custom object detection implementations registered to the motrack catalog. -Importing this package registers all detectors so they are available via DetectionManager. +Historically registered TDLP-side object-detection adapters. + +Now empty: as of motrack >= 0.7.0, ``mmdet_yolox`` is shipped and +registered by motrack itself. This package is kept only as an +import target for legacy callers (``import tdlp.object_detection``). """ -from tdlp.object_detection import mmdet_yolox # noqa: F401 diff --git a/tdlp/object_detection/mmdet_yolox.py b/tdlp/object_detection/mmdet_yolox.py deleted file mode 100644 index 5deb368..0000000 --- a/tdlp/object_detection/mmdet_yolox.py +++ /dev/null @@ -1,296 +0,0 @@ -""" -mmdetection-based YOLOX inference registered to the motrack object detection catalog. - -Supports: - - Standard mmdetection checkpoints (.pth) - - Legacy ByteTrack / original Megvii YOLOX checkpoints (.pth.tar) via key remapping -""" -from typing import Any, Optional, Tuple - -import numpy as np -import torch - -from motrack.object_detection.algorithms.base import ObjectDetectionInference -from motrack.object_detection.catalog import OBJECT_DETECTION_CATALOG -from motrack.utils.lookup import LookupTable - - -def _remap_bytetrack_state_dict(state_dict: dict) -> dict: - """ - Remap state-dict keys from the original YOLOX (Megvii / ByteTrack) format - to the mmdetection YOLOX format. - - ByteTrack packs both CSPDarknet and the FPN/PAN neck (YOLOPAFPN) under a - single ``backbone`` key. mmdetection separates them into ``backbone`` - (CSPDarknet only) and ``neck`` (YOLOXPAFPN). The head is renamed from - ``head`` to ``bbox_head`` and every sub-key gets a ``multi_level_`` prefix. - CSP block internals are also renamed (conv1→main_conv, etc.). - - Keys with no mmdetection equivalent (``head.stems``) are silently dropped; - ``neck.out_convs`` has no ByteTrack source and stays randomly-initialised. - """ - # ByteTrack dark stage index → mmdet stage index - _DARK_TO_STAGE = {'2': '1', '3': '2', '4': '3', '5': '4'} - - # ByteTrack CSP block internal key → mmdet CSPLayer key - _CSP_KEY_MAP = { - 'conv1': 'main_conv', - 'conv2': 'short_conv', - 'conv3': 'final_conv', - 'm': 'blocks', - } - - # ByteTrack neck component → mmdet neck component (preserving C3 blocks) - _NECK_COMPONENT_MAP = { - 'lateral_conv0': ('reduce_layers.0', False), - 'reduce_conv1': ('reduce_layers.1', False), - 'C3_p4': ('top_down_blocks.0', True), - 'C3_p3': ('top_down_blocks.1', True), - 'bu_conv2': ('downsamples.0', False), - 'bu_conv1': ('downsamples.1', False), - 'C3_n3': ('bottom_up_blocks.0', True), - 'C3_n4': ('bottom_up_blocks.1', True), - } - - # ByteTrack head component → mmdet head component - _HEAD_KEY_MAP = { - 'cls_convs': 'multi_level_cls_convs', - 'reg_convs': 'multi_level_reg_convs', - 'cls_preds': 'multi_level_conv_cls', - 'reg_preds': 'multi_level_conv_reg', - 'obj_preds': 'multi_level_conv_obj', - } - - def _remap_csp_suffix(suffix: str) -> str: - parts = suffix.split('.', 1) - if parts[0] in _CSP_KEY_MAP: - tail = ('.' + parts[1]) if len(parts) > 1 else '' - return _CSP_KEY_MAP[parts[0]] + tail - return suffix - - new_state_dict: dict = {} - skipped: list = [] - - for key, value in state_dict.items(): - - # ── backbone.backbone.stem.* → backbone.stem.* ────────────────────── - if key.startswith('backbone.backbone.stem.'): - new_key = 'backbone.stem.' + key[len('backbone.backbone.stem.'):] - - # ── backbone.backbone.darkN.* → backbone.stageM.* ────────────────── - elif key.startswith('backbone.backbone.dark'): - rest = key[len('backbone.backbone.dark'):] # e.g. '2.1.conv1.conv.weight' - dark_idx = rest[0] - if dark_idx not in _DARK_TO_STAGE: - skipped.append(key) - continue - stage_idx = _DARK_TO_STAGE[dark_idx] - sub_rest = rest[2:] # e.g. '1.conv1.conv.weight' - block_parts = sub_rest.split('.', 1) - block_idx = block_parts[0] - # dark2/3/4: [Conv(0), C3/CSPLayer(1)] - # dark5: [Conv(0), SPP(1), C3/CSPLayer(2)] - # CSP internal renaming applies only to the last (C3) block. - csp_block_idx = '2' if dark_idx == '5' else '1' - if block_idx == csp_block_idx and len(block_parts) > 1: - csp_suffix = _remap_csp_suffix(block_parts[1]) - new_key = f'backbone.stage{stage_idx}.{csp_block_idx}.{csp_suffix}' - else: - new_key = f'backbone.stage{stage_idx}.{sub_rest}' - - # ── backbone.NECK_COMP.* → neck.MMDET_COMP.* ──────────────────────── - elif key.startswith('backbone.'): - rest = key[len('backbone.'):] - matched = False - for bt_comp, (mmdet_comp, is_csp) in _NECK_COMPONENT_MAP.items(): - prefix = bt_comp + '.' - if rest == bt_comp or rest.startswith(prefix): - suffix = rest[len(bt_comp):] - if suffix.startswith('.'): - suffix = suffix[1:] - if is_csp and suffix: - suffix = _remap_csp_suffix(suffix) - new_key = f'neck.{mmdet_comp}' + (f'.{suffix}' if suffix else '') - matched = True - break - if not matched: - skipped.append(key) - continue - - # ── head.* → bbox_head.multi_level_*.* ────────────────────────────── - elif key.startswith('head.'): - rest = key[len('head.'):] - if rest.startswith('stems.'): - # head.stems in ByteTrack == neck.out_convs in mmdet - # (channel reduction before the detection head) - new_key = 'neck.out_convs.' + rest[len('stems.'):] - new_state_dict[new_key] = value - continue - matched = False - for bt_comp, mmdet_comp in _HEAD_KEY_MAP.items(): - prefix = bt_comp + '.' - if rest == bt_comp or rest.startswith(prefix): - suffix = rest[len(bt_comp):] # e.g. '.0.0.conv.weight' - new_key = f'bbox_head.{mmdet_comp}{suffix}' - matched = True - break - if not matched: - skipped.append(key) - continue - - else: - new_key = key - - new_state_dict[new_key] = value - - if skipped: - import logging - logging.getLogger(__name__).debug( - 'ByteTrack keys without mmdet equivalent (skipped): %s', skipped - ) - - return new_state_dict - - -@OBJECT_DETECTION_CATALOG.register('mmdet_yolox') -class MMDetYOLOXInference(ObjectDetectionInference): - """ - Object Detection – YOLOX via mmdetection. - - Parameters - ---------- - model_config : str - Path to an mmdetection Python config file (e.g. - ``configs/mmdet/yolox_x_bytetrack.py``). - model_path : str - Path to a checkpoint. Two formats are supported: - * Standard mmdet checkpoint (``.pth``) – used when - ``bytetrack_compat=False``. - * ByteTrack / original YOLOX checkpoint (``.pth.tar``) – used when - ``bytetrack_compat=True`` (the default). - accelerator : str - PyTorch device string, e.g. ``'cuda:0'`` or ``'cpu'``. - conf : float - Confidence threshold applied after inference. - min_bbox_area : int - Minimum bounding-box area (in pixels²) to keep a detection. - bytetrack_compat : bool - When ``True`` (default) the checkpoint is assumed to be in the - original YOLOX / ByteTrack format and key remapping is applied. - Set to ``False`` for native mmdetection checkpoints. - lookup : LookupTable, optional - Class-index → label string mapping. - """ - - def __init__( - self, - model_config: str, - model_path: str, - accelerator: str = 'cuda:0', - conf: float = 0.1, - min_bbox_area: int = 0, - bytetrack_compat: bool = True, - lookup: Optional[LookupTable] = None, - ) -> None: - super().__init__(lookup=lookup) - - try: - from mmdet.apis import init_detector - except ImportError as exc: - raise ImportError( - 'mmdetection is required for MMDetYOLOXInference. ' - 'Run: uv sync && uv run mim install "mmcv>=2.0.0"' - ) from exc - - # Initialise architecture without loading weights so we can load them - # manually (needed for the ByteTrack key-remapping path). - self._model = init_detector(model_config, checkpoint=None, device=accelerator) - - # Disable score filtering inside mmdet; we apply our own threshold. - self._model.test_cfg.score_thr = 0.0 - - if bytetrack_compat: - self._load_bytetrack_checkpoint(model_path) - else: - from mmengine.runner import load_checkpoint - load_checkpoint(self._model, model_path, map_location=accelerator) - - self._model.eval() - self._conf = conf - self._min_bbox_area = min_bbox_area - - # ------------------------------------------------------------------ - # Private helpers - # ------------------------------------------------------------------ - - def _load_bytetrack_checkpoint(self, path: str) -> None: - import logging - log = logging.getLogger(__name__) - - ckpt = torch.load(path, map_location='cpu', weights_only=False) - raw_state_dict = ckpt['model'] if 'model' in ckpt else ckpt - remapped = _remap_bytetrack_state_dict(raw_state_dict) - missing, unexpected = self._model.load_state_dict(remapped, strict=False) - - # neck.out_convs are present in mmdet YOLOX but not in ByteTrack YOLOX; - # they are randomly initialised and their absence is expected. - fatal_missing = [k for k in missing if not k.startswith('neck.out_convs')] - if fatal_missing: - raise RuntimeError( - f'Missing keys when loading ByteTrack checkpoint:\n{fatal_missing}\n' - 'The mmdet config may not match the checkpoint architecture.' - ) - if missing: - log.debug('Expected missing keys (randomly initialised): %s', missing) - if unexpected: - log.warning( - 'Unexpected keys in ByteTrack checkpoint (ignored): %s', unexpected - ) - - # ------------------------------------------------------------------ - # ObjectDetectionInference interface - # ------------------------------------------------------------------ - - def predict_raw(self, image: np.ndarray) -> Any: - """Run mmdetection inference and return raw DetDataSample.""" - from mmdet.apis import inference_detector - with torch.no_grad(): - return inference_detector(self._model, image) - - def postprocess( - self, image: np.ndarray, raw: Any - ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: - """ - Convert mmdetection output to the motrack format. - - Returns - ------- - bboxes_xyxy : np.ndarray, shape (N, 4), float32 - Normalised bounding boxes [x1, y1, x2, y2] in [0, 1]. - classes : np.ndarray, shape (N,), float32 - Class indices. - confidences : np.ndarray, shape (N,), float32 - Confidence scores. - """ - pred = raw.pred_instances - bboxes = pred.bboxes.cpu().numpy().astype(np.float32) # (N, 4) pixel xyxy - scores = pred.scores.cpu().numpy().astype(np.float32) # (N,) - labels = pred.labels.cpu().numpy().astype(np.float32) # (N,) - - # Confidence filter - mask = scores >= self._conf - bboxes, scores, labels = bboxes[mask], scores[mask], labels[mask] - - # Min-area filter (pixel area before normalisation) - if self._min_bbox_area > 0: - areas = (bboxes[:, 2] - bboxes[:, 0]) * (bboxes[:, 3] - bboxes[:, 1]) - mask = areas >= self._min_bbox_area - bboxes, scores, labels = bboxes[mask], scores[mask], labels[mask] - - # Normalise coordinates to [0, 1] - h, w = image.shape[:2] - bboxes[:, [0, 2]] /= w - bboxes[:, [1, 3]] /= h - bboxes = np.clip(bboxes, 0.0, 1.0) - - return bboxes, labels, scores diff --git a/tdlp/tracker/__init__.py b/tdlp/tracker/__init__.py index ea30893..c1fd303 100644 --- a/tdlp/tracker/__init__.py +++ b/tdlp/tracker/__init__.py @@ -4,6 +4,7 @@ """ from tdlp.tracker.online import TDLPOnlineTracker from tdlp.tracker.offline import TDLPOfflineTracker +from tdlp.tracker import adapter # noqa: F401 — registers 'tdlp' in TRACKER_CATALOG __all__ = [ 'TDLPOnlineTracker', diff --git a/tdlp/tracker/adapter.py b/tdlp/tracker/adapter.py new file mode 100644 index 0000000..93d39e4 --- /dev/null +++ b/tdlp/tracker/adapter.py @@ -0,0 +1,105 @@ +""" +Adapter that registers the TDLP tracker in Motrack's TRACKER_CATALOG. +Loads model + transform from config in __init__, so the tracker is +fully self-contained and instantiable via motrack.tracker.tracker_factory. +""" +from typing import Any, Dict, Optional + +import torch +from hydra.utils import instantiate +from motrack.tracker.trackers.catalog import TRACKER_CATALOG +from omegaconf import OmegaConf +from pydantic import BaseModel, ConfigDict, Field +from torch import nn + +from tdlp.datasets.dataset.transform import IdentityTransform, Transform +from tdlp.tracker.online import TDLPOnlineTracker + +# Module-level model cache — keyed by checkpoint path. +# Required for optimization: without this, a 100-trial run reloads the +# checkpoint from disk 100 times. +_MODEL_CACHE: Dict[str, nn.Module] = {} + + +@TRACKER_CATALOG.register_config('tdlp') +class TDLPTrackerConfig(BaseModel): + """ + Config schema for the TDLP tracker. + + NOTE: The architecture-config field is named ``architecture`` (not + ``model_config``) because Pydantic v2 reserves ``model_config`` as + the class-level ConfigDict slot (see ``model_config = ConfigDict(...)`` + below). + """ + + # Pydantic v2 class-level config — not a regular field. + model_config = ConfigDict(extra='forbid') + + # --- Fixed: model / transform / device (NOT optimizable) --- + architecture: Dict[str, Any] # Hydra-instantiatable; has _target_ + checkpoint: str + device: str = 'cpu' + transform: Optional[Dict[str, Any]] = None # Hydra-instantiatable; None → Identity + + # --- Optimizable: tracker hyperparams --- + detection_threshold: float = Field(default=0.4, ge=0.0, le=1.0) + sim_threshold: float = Field(default=0.5, ge=0.0, le=1.0) + initialization_threshold: int = Field(default=1, ge=0) + remember_threshold: int = Field(default=30, ge=1) + new_tracklet_detection_threshold: float = Field(default=0.9, ge=0.0, le=1.0) + use_conf: bool = True + + # ---- Builders --------------------------------------------------------- + def build_model(self) -> nn.Module: + """Build and load the TDLP model. Cached by checkpoint path.""" + if self.checkpoint in _MODEL_CACHE: + model = _MODEL_CACHE[self.checkpoint] + else: + model = instantiate(OmegaConf.create(self.architecture)) + state_dict = torch.load(self.checkpoint, map_location='cpu') + model.load_state_dict(state_dict['model']) + _MODEL_CACHE[self.checkpoint] = model + # Move to configured device for this trial. Cheap when already there; + # correct after a previous trial released it to CPU in __del__. + model.to(self.device) + return model + + def build_transform(self) -> Transform: + """Build the TDLP feature transform.""" + if self.transform is None: + return IdentityTransform() + return instantiate(OmegaConf.create(self.transform)) + + +@TRACKER_CATALOG.register('tdlp') +class TDLPAdapterTracker(TDLPOnlineTracker): + """Self-contained TDLP tracker; loads model/transform from config.""" + + def __init__(self, config: TDLPTrackerConfig): + self._cached_checkpoint = config.checkpoint # for __del__ + model = config.build_model() + transform = config.build_transform() + + super().__init__( + transform=transform, + model=model, + device=config.device, + detection_threshold=config.detection_threshold, + sim_threshold=config.sim_threshold, + initialization_threshold=config.initialization_threshold, + remember_threshold=config.remember_threshold, + new_tracklet_detection_threshold=config.new_tracklet_detection_threshold, + use_conf=config.use_conf, + ) + + def __del__(self): + # When this trial's tracker is GC'd, push the cached model back to CPU + # so GPU memory is freed for the next trial. The next trial's + # build_model will move it back to the configured device. + try: + cached = _MODEL_CACHE.get(self._cached_checkpoint) + if cached is not None: + cached.to('cpu') + except Exception: + # __del__ must not raise during interpreter shutdown + pass diff --git a/tdlp/tracker/offline.py b/tdlp/tracker/offline.py index 4dd5c10..0b6d970 100644 --- a/tdlp/tracker/offline.py +++ b/tdlp/tracker/offline.py @@ -38,7 +38,6 @@ def __init__( sim_threshold: float = 0.5, initialization_threshold: int = 1, remember_threshold: int = 30, - clip_length: Optional[int] = None, new_tracklet_detection_threshold: float = 0.9, use_conf: bool = True ): @@ -52,7 +51,6 @@ def __init__( sim_threshold: Similarity threshold to use for tracking. initialization_threshold: Initialization threshold to use for tracking. remember_threshold: Remember threshold to use for tracking. - clip_length: Clip length to use for tracking. new_tracklet_detection_threshold: New tracklet detection threshold to use for tracking. use_conf: Use confidence threshold to filter detections. @@ -68,7 +66,6 @@ def __init__( sim_threshold=sim_threshold, initialization_threshold=initialization_threshold, remember_threshold=remember_threshold, - clip_length=clip_length, new_tracklet_detection_threshold=new_tracklet_detection_threshold, use_conf=use_conf ) diff --git a/tdlp/tracker/online.py b/tdlp/tracker/online.py index 62d9c68..ceb19d1 100644 --- a/tdlp/tracker/online.py +++ b/tdlp/tracker/online.py @@ -45,7 +45,6 @@ def __init__( sim_threshold: float = 0.5, initialization_threshold: int = 1, remember_threshold: int = 30, - clip_length: Optional[int] = None, new_tracklet_detection_threshold: float = 0.9, use_conf: bool = True ): @@ -58,7 +57,6 @@ def __init__( sim_threshold: Similarity threshold to use for tracking. initialization_threshold: Initialization threshold to use for tracking. remember_threshold: Remember threshold to use for tracking. - clip_length: Clip length to use for tracking. new_tracklet_detection_threshold: New tracklet detection threshold to use for tracking. use_conf: Use confidence threshold to filter detections. @@ -82,7 +80,6 @@ def __init__( self._initialization_threshold = initialization_threshold self._remember_threshold = remember_threshold - self._clip_length = clip_length if clip_length is not None else self._remember_threshold self._new_tracklet_detection_threshold = new_tracklet_detection_threshold self._next_id = 0 @@ -117,19 +114,19 @@ def _convert_data( N = max(n_tracks, n_detections) # (2) Observed data conversion - observed_ts = torch.zeros(N, self._clip_length, dtype=torch.long) - observed_temporal_mask = torch.ones(N, self._clip_length, dtype=torch.bool) + observed_ts = torch.zeros(N, self._remember_threshold, dtype=torch.long) + observed_temporal_mask = torch.ones(N, self._remember_threshold, dtype=torch.bool) observed_features = PredictionBBoxFeatureExtractor.initialize_features( feature_names=self._feature_names, n_tracks=N, - temporal_length=self._clip_length, + temporal_length=self._remember_threshold, ) - time_offset = frame_index - self._clip_length + time_offset = frame_index - self._remember_threshold for t_i, tracklet in enumerate(tracklets): indices = [] frame_indices = [] - bbox_values = [] + per_frame_data = [] for frame_info in tracklet.history: relative_index = frame_info.frame_index - time_offset @@ -138,17 +135,21 @@ def _convert_data( indices.append(relative_index) frame_indices.append(frame_info.frame_index) - data = frame_info.data - if SupportedFeatures.BBOX in self._feature_names: - bbox_values.append([*data['bbox_xywh'], data['bbox_conf']]) + per_frame_data.append(frame_info.data) if not indices: continue observed_ts[t_i, indices] = torch.tensor(frame_indices, dtype=torch.long) observed_temporal_mask[t_i, indices] = False - if bbox_values: - observed_features['bbox'][t_i, indices, :] = torch.tensor(bbox_values, dtype=torch.float32) + for relative_idx, data in zip(indices, per_frame_data): + PredictionBBoxFeatureExtractor.set_features( + feature_names=self._feature_names, + features=observed_features, + object_index=t_i, + clip_index=relative_idx, + data=data, + ) # (3) Unobserved data conversion unobserved_features = PredictionBBoxFeatureExtractor.initialize_features( @@ -162,9 +163,14 @@ def _convert_data( unobserved_ts[:n_detections] = frame_index unobserved_temporal_mask[:n_detections] = False - if n_detections > 0 and SupportedFeatures.BBOX in self._feature_names: - det_bbox_values = [[*data['bbox_xywh'], data['bbox_conf']] for data in objects_data] - unobserved_features['bbox'][:n_detections, 0, :] = torch.tensor(det_bbox_values, dtype=torch.float32) + for d_i, data in enumerate(objects_data): + PredictionBBoxFeatureExtractor.set_features( + feature_names=self._feature_names, + features=unobserved_features, + object_index=d_i, + clip_index=0, + data=data, + ) # Remove temporal dimension unobserved_features = {k: v[:, 0] for k, v in unobserved_features.items()} @@ -184,6 +190,7 @@ def _convert_data( ) ) + @torch.no_grad() def _association( self, tracklets: List[Tracklet], @@ -337,7 +344,7 @@ def _track( frame_index=frame_index, _id=self._next_id, state=TrackletState.NEW if frame_index > self._initialization_threshold else TrackletState.ACTIVE, - max_history=self._clip_length - 1, + max_history=self._remember_threshold - 1, frame_data=data ) self._next_id += 1 diff --git a/tdlp/trainer/end_to_end_trainer.py b/tdlp/trainer/end_to_end_trainer.py new file mode 100644 index 0000000..0333b25 --- /dev/null +++ b/tdlp/trainer/end_to_end_trainer.py @@ -0,0 +1,536 @@ +""" +End-to-end autoregressive trainer for TDLP. + +Problem (exposure bias): + Standard training feeds ground-truth track histories to the model, but during + inference the tracker builds histories from its own (possibly wrong) association + predictions. When histories are short or error-prone (video start, objects that + frequently appear/disappear), this distribution mismatch degrades performance. + +Solution: + This trainer simulates the inference loop during training. Given a clip of T+1 + frames it processes them autoregressively: + + 1. Frame 0 -- initialise one track per present detection. + 2. For each subsequent frame t = 1 .. T: + a. Build a ``VideoClipData`` from the *current* track history and the + frame-t detections, then apply the data transform (including FoD, + which depends on the actual -- possibly wrong -- history). + b. Run the model forward pass. + c. Compute the association cost matrix via ``model.compute_cost_matrix`` + and solve with Hungarian matching. + d. Update track histories with the matched detections. Unmatched + detections become new tracks; unmatched tracks keep their history. + 3. Return the averaged loss from the selected gradient frames. + + Because the transform has temporal dependencies (finite-order differences) + and the association errors compound over time, the model learns to operate + on the kind of noisy histories it actually encounters at inference. + +Gradient frame selection: + Not every autoregressive step needs to contribute gradients. The + ``n_gradient_frames`` parameter selects an evenly-spaced subset of steps + (always including the last). Steps outside this set run under + ``torch.no_grad()``, which keeps VRAM usage at roughly + ``n_gradient_frames x single_forward_pass``. + + Formula: ``{total_steps * (i + 1) // n for i in range(n)}`` + Examples (50 steps): n=1 -> {50}, n=2 -> {25, 50}, n=3 -> {17, 34, 50} + +Identity supervision contract: + After a wrong association a track's ``assigned_id`` may diverge from its + original object. The BCE loss at subsequent steps uses this *noisy* ID for + supervision. This is a deliberate approximation -- it mirrors the same + noise the model sees during inference and teaches it to be robust to + accumulated association errors. + +Workflow: + Pretrain with ``ContrastiveTrainer``, then fine-tune with + ``EndToEndTrainer``. The pretrained model's similarity threshold is reused + as the ``sim_threshold`` for Hungarian matching during E2E training. +""" +import logging +from dataclasses import dataclass, field +from typing import Any, Dict, List, Optional, Set, Tuple + +import numpy as np +import torch +from torch import nn +from torch.cuda.amp import autocast +from torch.optim import Optimizer +from torch.optim.lr_scheduler import LRScheduler + +from motrack.tracker.matching.utils import hungarian + +from tdlp.architectures.tdlp.base import TDLPModel +from tdlp.datasets.dataset.common.data import VideoClipData, VideoClipPart +from tdlp.datasets.dataset.transform import Transform +from tdlp.trainer.trainer import ContrastiveTrainer +from tdlp.trainer import torch_distrib_utils, torch_helper + +logger = logging.getLogger('EndToEndTrainer') + + +@dataclass +class TrackState: + """Mutable track-history state carried across autoregressive steps. + + All tensors share the same batch (B) and track-slot (N) dimensions. + The history buffer has a fixed temporal length equal to the clip length T. + New observations are appended at the *last* position; when the buffer is + full the oldest entry is shifted out. + + Attributes: + raw_features: ``{key: (B, N, T, F_key)}`` -- raw (pre-transform) features. + mask: ``(B, N, T)`` -- ``True`` = missing / padded entry. + ts: ``(B, N, T)`` -- frame timestamps for each history slot. + assigned_ids: ``(B, N)`` -- the identity label currently assigned to each + track (updated on every match; may diverge from ground truth after + a wrong association -- see module docstring on identity supervision). + active: ``(B, N)`` -- whether each track slot is in use. + """ + raw_features: Dict[str, torch.Tensor] + mask: torch.Tensor + ts: torch.Tensor + assigned_ids: torch.Tensor + active: torch.Tensor + + +class EndToEndTrainer(ContrastiveTrainer): + """Autoregressive end-to-end trainer for TDLP. + + Overrides :meth:`_forward_and_loss` to process frames sequentially, + building track histories from the model's own association predictions + (via Hungarian matching) rather than from ground-truth data. + + See the module docstring for a full description of the algorithm, + gradient frame selection, and the identity supervision contract. + """ + + def __init__( + self, + model: nn.Module, + loss_func: nn.Module, + optimizer: Optimizer, + scheduler: LRScheduler, + n_epochs: int, + tensorboard_log_dirpath: str, + checkpoints_dirpath: str, + transform: Transform, + n_gradient_frames: int = 1, + sim_threshold: float = 0.5, + metric_monitor: str = 'val-epoch/loss', + metric_monitor_minimize: bool = True, + gradient_clip: Optional[float] = None, + mixed_precision: bool = False, + device: Optional[str] = None + ): + """ + Args: + transform: Data transform to apply per autoregressive step. + The dataset must be loaded with disable_transform=True. + n_gradient_frames: Number of evenly-spaced frames that compute gradients. + 1 = only last frame, 2 = middle + last, etc. + sim_threshold: Association threshold for Hungarian matching (from pretrained model). + """ + super().__init__( + model=model, + loss_func=loss_func, + optimizer=optimizer, + scheduler=scheduler, + n_epochs=n_epochs, + tensorboard_log_dirpath=tensorboard_log_dirpath, + checkpoints_dirpath=checkpoints_dirpath, + metric_monitor=metric_monitor, + metric_monitor_minimize=metric_monitor_minimize, + gradient_clip=gradient_clip, + mixed_precision=mixed_precision, + device=device + ) + self._e2e_transform = transform + self._n_gradient_frames = n_gradient_frames + self._sim_threshold = sim_threshold + + @staticmethod + def _get_gradient_step_indices(total_steps: int, n_gradient_frames: int) -> Set[int]: + """ + Compute evenly-spaced gradient step indices, always including the last step. + + Args: + total_steps: Total number of autoregressive steps (1-indexed). + n_gradient_frames: Desired number of gradient frames. + + Returns: + Set of 1-indexed step indices where gradients should be computed. + """ + n = min(n_gradient_frames, total_steps) + return {total_steps * (i + 1) // n for i in range(n)} + + def _init_track_state( + self, + B: int, + N: int, + history_len: int, + feature_shapes: Dict[str, int], + device: torch.device, + ) -> TrackState: + """Initialize empty track state buffers.""" + raw_features = { + key: torch.zeros(B, N, history_len, F, device=device) + for key, F in feature_shapes.items() + } + return TrackState( + raw_features=raw_features, + mask=torch.ones(B, N, history_len, dtype=torch.bool, device=device), + ts=torch.zeros(B, N, history_len, dtype=torch.long, device=device), + assigned_ids=torch.full((B, N), -1, dtype=torch.long, device=device), + active=torch.zeros(B, N, dtype=torch.bool, device=device), + ) + + def _initialize_tracks_from_detections( + self, + state: TrackState, + det_features: Dict[str, torch.Tensor], + det_mask: torch.Tensor, + det_ids: torch.Tensor, + det_ts: torch.Tensor, + ) -> None: + """ + Initialize tracks from frame-0 detections (vectorized). + + All present detections at frame 0 become tracks with 1-frame history + placed at the last position of the history buffer. + """ + present = ~det_mask # (B, N) True where detection is present + for key in state.raw_features: + state.raw_features[key][:, :, -1, :][present] = det_features[key][present] + state.mask[:, :, -1][present] = False + state.ts[:, :, -1][present] = det_ts[present] + state.assigned_ids[present] = det_ids[present] + state.active[present] = True + + def _apply_transform_batched( + self, + state: TrackState, + det_features: Dict[str, torch.Tensor], + det_mask: torch.Tensor, + det_ts: torch.Tensor, + ) -> Tuple[Dict[str, torch.Tensor], torch.Tensor, Dict[str, torch.Tensor], torch.Tensor]: + """ + Apply transform per batch sample, then re-stack. + + Clones raw features before transform to prevent in-place mutation of state buffers. + + Returns: + (transformed_track_features, transformed_track_mask, + transformed_det_features, transformed_det_mask) + """ + B = state.mask.shape[0] + track_features_list = [] + track_mask_list = [] + det_features_list = [] + det_mask_list = [] + + for b in range(B): + obs_features = {k: v[b].clone() for k, v in state.raw_features.items()} + obs_mask = state.mask[b].clone() + obs_ts = state.ts[b].clone() + + unobs_features = {k: v[b].clone() for k, v in det_features.items()} + unobs_mask = det_mask[b].clone() + unobs_ts = det_ts[b].clone() + + clip_data = VideoClipData( + observed=VideoClipPart( + ids=None, + ts=obs_ts, + mask=obs_mask, + features=obs_features, + ), + unobserved=VideoClipPart( + ids=None, + ts=unobs_ts, + mask=unobs_mask, + features=unobs_features, + ), + ) + transformed = self._e2e_transform(clip_data) + + track_features_list.append(transformed.observed.features) + track_mask_list.append(transformed.observed.mask) + det_features_list.append(transformed.unobserved.features) + det_mask_list.append(transformed.unobserved.mask) + + feature_keys = list(track_features_list[0].keys()) + batched_track_features = { + k: torch.stack([t[k] for t in track_features_list]) + for k in feature_keys + } + batched_track_mask = torch.stack(track_mask_list) + + det_keys = list(det_features_list[0].keys()) + batched_det_features = { + k: torch.stack([d[k] for d in det_features_list]) + for k in det_keys + } + batched_det_mask = torch.stack(det_mask_list) + + return batched_track_features, batched_track_mask, batched_det_features, batched_det_mask + + def _compute_associations( + self, + model_output: Any, + state: TrackState, + det_mask: torch.Tensor, + ) -> List[Tuple[List[Tuple[int, int]], List[int], List[int]]]: + """ + Run Hungarian matching per batch element on model output. + + Returns: + List (one per batch element) of (matches, unmatched_tracks, unmatched_dets). + Indices are in padded (N-dim) space. + """ + B = det_mask.shape[0] + unwrapped: TDLPModel = torch_distrib_utils.get_model(self._model) + cost_matrix_batch = unwrapped.compute_cost_matrix( + model_output, + n_tracks=det_mask.shape[1], + n_dets=det_mask.shape[1], + ) + + results: List[Tuple[List[Tuple[int, int]], List[int], List[int]]] = [] + for b in range(B): + active_indices = state.active[b].nonzero(as_tuple=True)[0].tolist() + det_indices = (~det_mask[b]).nonzero(as_tuple=True)[0].tolist() + + n_active = len(active_indices) + n_dets = len(det_indices) + + if n_active == 0: + results.append(([], [], det_indices)) + continue + if n_dets == 0: + results.append(([], active_indices, [])) + continue + + sub_cost = cost_matrix_batch[b, active_indices][:, det_indices].cpu().numpy() + sub_cost[sub_cost > self._sim_threshold] = np.inf + sub_matches, sub_unmatched_tracks, sub_unmatched_dets = hungarian(sub_cost) + + matches = [(active_indices[t], det_indices[d]) for t, d in sub_matches] + unmatched_tracks = [active_indices[t] for t in sub_unmatched_tracks] + unmatched_dets = [det_indices[d] for d in sub_unmatched_dets] + results.append((matches, unmatched_tracks, unmatched_dets)) + + return results + + def _update_track_state( + self, + state: TrackState, + associations: List[Tuple[List[Tuple[int, int]], List[int], List[int]]], + det_features: Dict[str, torch.Tensor], + det_mask: torch.Tensor, + det_ids: torch.Tensor, + det_ts: torch.Tensor, + ) -> None: + """ + Update track state based on Hungarian matching results. + + - Matched tracks: shift history left, append matched detection at last position. + - Unmatched detections: assign to first free track slot with 1-frame history. + - Unmatched tracks: no change (persist with existing history). + """ + B = state.mask.shape[0] + + for b in range(B): + matches, _unmatched_tracks, unmatched_dets = associations[b] + + # Matched tracks: shift history and append new detection + for t_idx, d_idx in matches: + # Shift history left by 1 + for key in state.raw_features: + state.raw_features[key][b, t_idx, :-1] = state.raw_features[key][b, t_idx, 1:].clone() + state.raw_features[key][b, t_idx, -1] = det_features[key][b, d_idx].detach() + state.mask[b, t_idx, :-1] = state.mask[b, t_idx, 1:].clone() + state.mask[b, t_idx, -1] = False + state.ts[b, t_idx, :-1] = state.ts[b, t_idx, 1:].clone() + state.ts[b, t_idx, -1] = det_ts[b, d_idx] + state.assigned_ids[b, t_idx] = det_ids[b, d_idx] + + # Unmatched detections: create new tracks in free slots + free_slots = (~state.active[b]).nonzero(as_tuple=True)[0] + slot_idx = 0 + for d_idx in unmatched_dets: + if det_mask[b, d_idx]: + continue + if slot_idx >= len(free_slots): + break + slot = free_slots[slot_idx].item() + slot_idx += 1 + + for key in state.raw_features: + state.raw_features[key][b, slot] = 0 + state.raw_features[key][b, slot, -1] = det_features[key][b, d_idx].detach() + state.mask[b, slot] = True + state.mask[b, slot, -1] = False + state.ts[b, slot] = 0 + state.ts[b, slot, -1] = det_ts[b, d_idx] + state.assigned_ids[b, slot] = det_ids[b, d_idx] + state.active[b, slot] = True + + @staticmethod + def _aggregate_loss_dicts( + loss_dicts: List[Dict[str, torch.Tensor]], + ) -> Dict[str, torch.Tensor]: + """Aggregate loss dicts from multiple gradient steps.""" + if not loss_dicts: + raise RuntimeError('No gradient frames produced a loss.') + + agg: Dict[str, Any] = {} + n = len(loss_dicts) + + # Average scalar losses + for key in loss_dicts[0]: + if 'loss' in key: + agg[key] = sum(d[key] for d in loss_dicts) / n + elif key in ('track_labels', 'det_labels', 'track_predictions', 'det_predictions'): + tensors = [d[key] for d in loss_dicts if d[key] is not None and d[key].numel() > 0] + agg[key] = torch.cat(tensors) if tensors else torch.empty(0, dtype=torch.long) + elif key in ('track_mask', 'det_mask'): + agg[key] = None + else: + agg[key] = loss_dicts[-1][key] + + return agg + + def _forward_and_loss( + self, + data: Dict[str, torch.Tensor], + return_state: bool = False, + ) -> Dict[str, torch.Tensor]: + """Autoregressive forward pass. + + Receives **raw** (untransformed) batched clip data and processes frames + one-by-one, building track histories from predicted associations. + + Input shapes (batch dimension omitted for clarity):: + + observed.features : {key: (N, T, F)} -- raw features for T frames + observed.mask : (N, T) + observed.ids : (N, T) + unobserved.features: {key: (N, F)} -- detections at frame T + unobserved.mask : (N,) + unobserved.ids : (N,) + + The method merges these into T+1 frames, then: + - Frame 0 initialises tracks. + - Frames 1..T are processed autoregressively (see module docstring). + - Loss is accumulated only at gradient frames and averaged. + + Args: + data: Raw (untransformed) batched clip data from the DataLoader. + return_state: If ``True``, return ``(loss_dict, final_state)`` + instead of just ``loss_dict``. Useful for testing that the + autoregressive history matches ground truth when associations + are perfect. + + Returns: + Loss dict compatible with the training loop (same keys as + ``ContrastiveTrainer._forward_and_loss``). If *return_state* is + ``True``, returns a ``(loss_dict, TrackState)`` tuple. + """ + B, N, T = data['observed']['mask'].shape + device = data['observed']['mask'].device + + # 1. Merge observed + unobserved into all T+1 frames + all_features: Dict[str, torch.Tensor] = {} + for key in data['observed']['features']: + obs = data['observed']['features'][key] # (B, N, T, F) + unobs = data['unobserved']['features'][key] # (B, N, F) + all_features[key] = torch.cat([obs, unobs.unsqueeze(2)], dim=2) + + all_mask = torch.cat([ + data['observed']['mask'], + data['unobserved']['mask'].unsqueeze(2) + ], dim=2) # (B, N, T+1) + + all_ids = torch.cat([ + data['observed']['ids'], + data['unobserved']['ids'].unsqueeze(2) + ], dim=2) # (B, N, T+1) + + all_ts = torch.cat([ + data['observed']['ts'], + data['unobserved']['ts'].unsqueeze(2) + ], dim=2) # (B, N, T+1) + + total_steps = T # steps 1..T (step 0 is initialization) + + # 2. Gradient step indices + gradient_indices = self._get_gradient_step_indices(total_steps, self._n_gradient_frames) + + # 3. Initialize track state + feature_shapes = {key: v.shape[-1] for key, v in all_features.items()} + state = self._init_track_state(B, N, T, feature_shapes, device) + + # 4. Step 0: initialize tracks from frame-0 detections + frame0_features = {key: all_features[key][:, :, 0, :] for key in all_features} + frame0_mask = all_mask[:, :, 0] + frame0_ids = all_ids[:, :, 0] + frame0_ts = all_ts[:, :, 0] + self._initialize_tracks_from_detections( + state, frame0_features, frame0_mask, frame0_ids, frame0_ts + ) + + # 5. Autoregressive loop: steps 1..T + gradient_loss_dicts: List[Dict[str, torch.Tensor]] = [] + + for step_t in range(1, T + 1): + # a. Extract frame-t detections + det_features_t = {key: all_features[key][:, :, step_t, :] for key in all_features} + det_mask_t = all_mask[:, :, step_t] + det_ids_t = all_ids[:, :, step_t] + det_ts_t = all_ts[:, :, step_t] + + # Skip if no active tracks (shouldn't happen after step 0) + if not state.active.any(): + continue + + # b. Apply transform per batch sample + trans_track_feat, trans_track_mask, trans_det_feat, trans_det_mask = \ + self._apply_transform_batched(state, det_features_t, det_mask_t, det_ts_t) + + # c. Determine grad context + use_grad = (step_t in gradient_indices) and torch.is_grad_enabled() + context = torch.enable_grad() if use_grad else torch.no_grad() + + # d. Model forward + loss + with context: + track_ids_for_loss = state.assigned_ids.unsqueeze(-1).expand_as(state.mask) + + with autocast(enabled=self._mixed_precision): + loss_dict, model_output = self._compute_model_output_and_loss( + trans_track_feat, trans_track_mask, track_ids_for_loss, + trans_det_feat, trans_det_mask, det_ids_t + ) + + if use_grad: + gradient_loss_dicts.append(loss_dict) + + # e. Hungarian matching (always no grad) + with torch.no_grad(): + associations = self._compute_associations( + model_output, state, det_mask_t + ) + + # f. Update track state + self._update_track_state( + state, associations, + det_features_t, det_mask_t, det_ids_t, det_ts_t + ) + + # 6. Aggregate losses from gradient frames + loss_dict = self._aggregate_loss_dicts(gradient_loss_dicts) + if return_state: + return loss_dict, state + return loss_dict diff --git a/tdlp/trainer/factory.py b/tdlp/trainer/factory.py new file mode 100644 index 0000000..f7e1ff0 --- /dev/null +++ b/tdlp/trainer/factory.py @@ -0,0 +1,64 @@ +"""Trainer factory for building trainers from config.""" +from typing import Optional + +from torch import nn +from torch.optim import Optimizer +from torch.optim.lr_scheduler import LRScheduler + +from tdlp.datasets.dataset.transform import Transform +from tdlp.trainer.end_to_end_trainer import EndToEndTrainer +from tdlp.trainer.trainer import ContrastiveTrainer +from tdlp.trainer.types import TrainerType + + +def build_trainer( + trainer_type: TrainerType, + trainer_params: Optional[dict], + model: nn.Module, + loss_func: nn.Module, + optimizer: Optimizer, + scheduler: LRScheduler, + n_epochs: int, + gradient_clip: Optional[float], + mixed_precision: bool, + device: Optional[str], + tensorboard_log_dirpath: str, + checkpoints_dirpath: str, + metric_monitor: str, + transform: Optional[Transform] = None, +) -> ContrastiveTrainer: + """Build a trainer based on the trainer type. + + Args: + trainer_type: Which trainer to build. + trainer_params: Extra parameters forwarded to the trainer constructor + (e.g. n_gradient_frames, sim_threshold for E2E). + transform: Data transform, required for E2E trainer + (dataset must be loaded with disable_transform=True). + """ + common = dict( + model=model, + loss_func=loss_func, + optimizer=optimizer, + scheduler=scheduler, + n_epochs=n_epochs, + gradient_clip=gradient_clip, + mixed_precision=mixed_precision, + device=device, + tensorboard_log_dirpath=tensorboard_log_dirpath, + checkpoints_dirpath=checkpoints_dirpath, + metric_monitor=metric_monitor, + ) + + if trainer_type == TrainerType.DEFAULT: + assert trainer_params is None or len(trainer_params) == 0, \ + f'Default trainer does not accept trainer_params, got: {trainer_params}' + return ContrastiveTrainer(**common) + + if trainer_type == TrainerType.END_TO_END: + assert transform is not None, \ + 'E2E trainer requires a transform (dataset must have disable_transform=True)' + params = trainer_params or {} + return EndToEndTrainer(**common, transform=transform, **params) + + raise ValueError(f'Unknown trainer type: {trainer_type}') diff --git a/tdlp/trainer/trainer.py b/tdlp/trainer/trainer.py index 4f49d47..68f8ea6 100644 --- a/tdlp/trainer/trainer.py +++ b/tdlp/trainer/trainer.py @@ -6,7 +6,7 @@ import os from pathlib import Path import time -from typing import Any, Dict, Optional, Union +from typing import Any, Dict, Optional, Tuple, Union import torch from torch import distributed as dist @@ -18,12 +18,7 @@ from torch.utils.tensorboard import SummaryWriter from torch.utils.data import DataLoader -from tdlp.architectures.tdlp.core import ( - MultiModalTDCP, - MultiModalTDSP, - TrackDetectionContrastivePrediction, - TrackDetectionSimilarityPrediction, -) +from tdlp.architectures.tdlp.base import TDLPModel from tdlp.common.conventions import LAST_CKPT from tdlp.trainer import torch_distrib_utils from tdlp.trainer import torch_helper @@ -249,6 +244,32 @@ def eval(self, val_loader: 'DataLoader') -> Dict[str, Any]: return val_metrics + def _compute_model_output_and_loss( + self, + track_x: Any, + track_mask: torch.Tensor, + track_ids: torch.Tensor, + det_x: Any, + det_mask: torch.Tensor, + det_ids: torch.Tensor + ) -> Tuple[Dict[str, torch.Tensor], Any]: + """ + Run model forward pass and compute loss. + + Delegates output-to-loss bridging to the model's ``prepare_loss_inputs`` method + (see :class:`~tdlp.architectures.tdlp.base.TDLPModel`). + + Returns: + Tuple of (loss_dict, raw_model_output). + The raw model output is needed by EndToEndTrainer for association cost computation. + """ + with autocast(enabled=self._mixed_precision): + model_output = self._model(track_x, track_mask, det_x, det_mask) + unwrapped: TDLPModel = torch_distrib_utils.get_model(self._model) + loss_args = unwrapped.prepare_loss_inputs(model_output, track_mask, det_mask, track_ids, det_ids) + loss_dict = self._loss_func(*loss_args) + return loss_dict, model_output + def _forward_and_loss(self, data: Dict[str, torch.Tensor]) -> Dict[str, torch.Tensor]: track_x = data['observed']['features'] track_mask = data['observed']['mask'] @@ -257,46 +278,10 @@ def _forward_and_loss(self, data: Dict[str, torch.Tensor]) -> Dict[str, torch.Te det_mask = data['unobserved']['mask'] det_ids = data['unobserved']['ids'] - with autocast(enabled=self._mixed_precision): - model_output = self._model(track_x, track_mask, det_x, det_mask) - # TODO: Refactor - if isinstance(self._model, (MultiModalTDCP, TrackDetectionContrastivePrediction)): - if isinstance(self._model, MultiModalTDCP): - track_features, det_features, track_feat_dict, det_feat_dict = model_output - else: - track_features, det_features = model_output - track_feat_dict = None - det_feat_dict = None - - loss_dict = self._loss_func( - track_features, - det_features, - track_mask, - det_mask, - track_feat_dict, - det_feat_dict, - track_ids, - det_ids - ) - elif isinstance(self._model, (MultiModalTDSP, TrackDetectionSimilarityPrediction)): - if isinstance(self._model, MultiModalTDSP): - logits, logits_dict = model_output - else: - logits = model_output - logits_dict = None - - loss_dict = self._loss_func( - logits, - track_mask, - det_mask, - track_ids, - det_ids, - logits_dict - ) - else: - raise TypeError(f'Unsupported model type: {type(self._model)}') - - return loss_dict + loss_dict, _ = self._compute_model_output_and_loss( + track_x, track_mask, track_ids, det_x, det_mask, det_ids + ) + return loss_dict def _train_epoch(self, train_loader: 'DataLoader') -> Dict[str, float]: """ diff --git a/tdlp/trainer/types.py b/tdlp/trainer/types.py new file mode 100644 index 0000000..a27ff5a --- /dev/null +++ b/tdlp/trainer/types.py @@ -0,0 +1,7 @@ +"""Trainer type definitions.""" +from enum import Enum + + +class TrainerType(str, Enum): + DEFAULT = 'default' + END_TO_END = 'end_to_end' diff --git a/tests/test_association_utils.py b/tests/test_association_utils.py new file mode 100644 index 0000000..7e8ccae --- /dev/null +++ b/tests/test_association_utils.py @@ -0,0 +1,85 @@ +"""Tests for model.compute_cost_matrix (TDLPModel interface).""" +import torch +from torch.nn import functional as F + +from tdlp.architectures.tdlp.core import build_mm_tdsp_model, build_mm_tdcp_model + + +def _build_small_tdsp(): + return build_mm_tdsp_model( + per_feature_params={'bbox': { + 'feature_encoder_type': 'motion', + 'feature_encoder_params': {'input_dim': 5}, + }}, + common_params={ + 'hidden_dim': 16, 'dropout': 0.0, + 'track_encoder_n_heads': 2, 'track_encoder_n_layers': 1, + 'track_encoder_ffn_dim': 32, 'projector_intermediate_dim': 16, + }, + sph_per_feature_params={'bbox': {'hidden_dim': 16}}, + sph_common_params={'hidden_dim': 16}, + mm_dim=16, + similarity_prediction_head_hidden_dim=16, + similarity_head_type='compact_mlp', + aggregator_type='sum', + aggregator_params={}, + ) + + +def _build_small_tdcp(): + return build_mm_tdcp_model( + per_feature_params={'bbox': { + 'feature_encoder_type': 'motion', + 'feature_encoder_params': {'input_dim': 5}, + }}, + common_params={ + 'hidden_dim': 16, 'dropout': 0.0, + 'track_encoder_n_heads': 2, 'track_encoder_n_layers': 1, + 'track_encoder_ffn_dim': 32, 'projector_intermediate_dim': 16, + }, + mm_dim=16, + aggregator_type='sum', + aggregator_params={}, + ) + + +class TestComputeCostMatrixTDSP: + def test_returns_correct_shape(self): + model = _build_small_tdsp() + logits = torch.randn(2, 5, 5) + cost = model.compute_cost_matrix((logits, None), n_tracks=3, n_dets=4) + assert cost.shape == (2, 3, 4) + + def test_values_in_zero_one(self): + model = _build_small_tdsp() + logits = torch.randn(2, 5, 5) + cost = model.compute_cost_matrix((logits, None), n_tracks=5, n_dets=5) + assert (cost >= 0).all() and (cost <= 1).all() + + def test_high_logits_give_low_cost(self): + model = _build_small_tdsp() + logits = torch.full((1, 3, 3), 10.0) + cost = model.compute_cost_matrix((logits, None), n_tracks=3, n_dets=3) + assert (cost < 0.01).all() + + +class TestComputeCostMatrixTDCP: + def test_returns_correct_shape(self): + model = _build_small_tdcp() + track_feat = torch.randn(2, 5, 16) + det_feat = torch.randn(2, 5, 16) + cost = model.compute_cost_matrix((track_feat, det_feat, None, None), n_tracks=3, n_dets=4) + assert cost.shape == (2, 3, 4) + + def test_values_in_zero_one(self): + model = _build_small_tdcp() + track_feat = torch.randn(2, 5, 16) + det_feat = torch.randn(2, 5, 16) + cost = model.compute_cost_matrix((track_feat, det_feat, None, None), n_tracks=5, n_dets=5) + assert (cost >= 0).all() and (cost <= 1).all() + + def test_identical_embeddings_zero_cost(self): + model = _build_small_tdcp() + feat = F.normalize(torch.randn(1, 3, 16), dim=-1) + cost = model.compute_cost_matrix((feat, feat, None, None), n_tracks=3, n_dets=3) + assert torch.allclose(cost.diagonal(dim1=1, dim2=2), torch.zeros(1, 3), atol=1e-5) diff --git a/tests/test_end_to_end_trainer.py b/tests/test_end_to_end_trainer.py new file mode 100644 index 0000000..ca722bf --- /dev/null +++ b/tests/test_end_to_end_trainer.py @@ -0,0 +1,430 @@ +"""Tests for the EndToEndTrainer.""" +from unittest.mock import patch +import pytest +import torch + +from tdlp.architectures.tdlp.core import build_mm_tdsp_model +from tdlp.datasets.dataset.common.data import VideoClipData, VideoClipPart +from tdlp.datasets.dataset.transform import ComposeTransform, IdentityTransform +from tdlp.datasets.dataset.transform.bbox import BBoxXYWHtoXYXY, FeatureFODStandardization +from tdlp.trainer.end_to_end_trainer import EndToEndTrainer, TrackState +from tdlp.trainer.losses.bce import ClipLevelBCE +from tdlp.trainer import torch_helper + + +# --- Helpers --- + +def _build_small_tdsp(): + return build_mm_tdsp_model( + per_feature_params={'bbox': { + 'feature_encoder_type': 'motion', + 'feature_encoder_params': {'input_dim': 5}, + }}, + common_params={ + 'hidden_dim': 16, 'dropout': 0.0, + 'track_encoder_n_heads': 2, 'track_encoder_n_layers': 1, + 'track_encoder_ffn_dim': 32, 'projector_intermediate_dim': 16, + }, + sph_per_feature_params={'bbox': {'hidden_dim': 16}}, + sph_common_params={'hidden_dim': 16}, + mm_dim=16, + similarity_prediction_head_hidden_dim=16, + similarity_head_type='compact_mlp', + aggregator_type='sum', + aggregator_params={}, + ) + + +def _build_fod_transform(): + """Build an FOD transform that converts 5D raw features to 10D (5 coords + 5 FoD).""" + return ComposeTransform([ + FeatureFODStandardization( + coord_mean={'bbox': [0.5, 0.5, 0.5, 0.5, 0.5]}, + coord_std={'bbox': [0.1, 0.1, 0.1, 0.1, 1.0]}, + fod_mean={'bbox': [0.0, 0.0, 0.0, 0.0, 0.0]}, + fod_std={'bbox': [0.05, 0.05, 0.05, 0.05, 1.0]}, + fod_time_scaled=False, + ) + ]) + + +def _build_e2e_trainer(model=None, loss_func=None, transform=None, n_gradient_frames=1): + if model is None: + model = _build_small_tdsp() + if loss_func is None: + loss_func = ClipLevelBCE() + if transform is None: + transform = _build_fod_transform() + + optimizer = torch.optim.Adam(model.parameters(), lr=1e-3) + scheduler = torch.optim.lr_scheduler.ConstantLR(optimizer, factor=1.0) + return EndToEndTrainer( + model=model, + loss_func=loss_func, + optimizer=optimizer, + scheduler=scheduler, + n_epochs=1, + tensorboard_log_dirpath='/tmp/test_e2e_tb', + checkpoints_dirpath='/tmp/test_e2e_ckpt', + device='cpu', + transform=transform, + n_gradient_frames=n_gradient_frames, + sim_threshold=0.9, + ) + + +def _build_raw_batch(B=2, N=4, T=5, F=5): + """Build a synthetic raw (untransformed) batch. + + All N objects present at all T+1 frames with unique IDs 0..N-1. + """ + return { + 'observed': { + 'features': {'bbox': torch.rand(B, N, T, F)}, + 'mask': torch.zeros(B, N, T, dtype=torch.bool), + 'ids': torch.arange(N).unsqueeze(0).unsqueeze(-1).expand(B, N, T).clone(), + 'ts': torch.arange(T).unsqueeze(0).unsqueeze(0).expand(B, N, T).clone(), + }, + 'unobserved': { + 'features': {'bbox': torch.rand(B, N, F)}, + 'mask': torch.zeros(B, N, dtype=torch.bool), + 'ids': torch.arange(N).unsqueeze(0).expand(B, N).clone(), + 'ts': torch.full((B, N), T, dtype=torch.long), + } + } + + +def _build_raw_batch_with_masking(B=2, N=4, T=5, F=5): + """Build batch where some objects appear/disappear mid-clip. + + Object 0: present at all frames + Object 1: appears at frame 2 + Object 2: present at all frames + Object 3: masked at all frames (padding) + """ + batch = _build_raw_batch(B, N, T, F) + # Object 1 absent before frame 2 + batch['observed']['mask'][:, 1, :2] = True + batch['observed']['features']['bbox'][:, 1, :2, :] = 0 + # Object 3 fully masked (padding) + batch['observed']['mask'][:, 3, :] = True + batch['observed']['features']['bbox'][:, 3, :, :] = 0 + batch['unobserved']['mask'][:, 3] = True + batch['unobserved']['features']['bbox'][:, 3, :] = 0 + batch['unobserved']['ids'][:, 3] = -1 + batch['observed']['ids'][:, 3, :] = -1 + return batch + + +# --- Gradient Step Index Tests --- + +class TestGradientStepIndices: + def test_single(self): + indices = EndToEndTrainer._get_gradient_step_indices(total_steps=10, n_gradient_frames=1) + assert indices == {10} + + def test_two(self): + indices = EndToEndTrainer._get_gradient_step_indices(total_steps=10, n_gradient_frames=2) + assert 10 in indices + assert len(indices) == 2 + + def test_three(self): + indices = EndToEndTrainer._get_gradient_step_indices(total_steps=9, n_gradient_frames=3) + assert indices == {3, 6, 9} + + def test_all_when_n_exceeds_total(self): + indices = EndToEndTrainer._get_gradient_step_indices(total_steps=5, n_gradient_frames=10) + assert indices == {1, 2, 3, 4, 5} + + def test_always_includes_last(self): + for total in [3, 5, 10, 50]: + for n in [1, 2, 3, 5]: + indices = EndToEndTrainer._get_gradient_step_indices(total, n) + assert total in indices + + +# --- Transform Application Tests --- + +class TestApplyTransformBatched: + def test_preserves_raw_features(self): + """Transform should not modify the raw feature buffers (clone boundary).""" + transform = ComposeTransform([BBoxXYWHtoXYXY()]) + trainer = _build_e2e_trainer(transform=transform) + + state = trainer._init_track_state(B=2, N=3, history_len=4, feature_shapes={'bbox': 5}, device='cpu') + state.raw_features['bbox'][:] = torch.rand_like(state.raw_features['bbox']) + state.mask[:, :, -1] = False # last slot has data + raw_copy = state.raw_features['bbox'].clone() + + det_features = {'bbox': torch.rand(2, 3, 5)} + det_mask = torch.zeros(2, 3, dtype=torch.bool) + det_ts = torch.ones(2, 3, dtype=torch.long) + + trainer._apply_transform_batched(state, det_features, det_mask, det_ts) + + assert torch.equal(state.raw_features['bbox'], raw_copy), 'Raw features mutated by transform' + + +# --- Forward and Loss Integration Tests --- + +class TestForwardAndLoss: + def test_returns_correct_keys(self): + trainer = _build_e2e_trainer(n_gradient_frames=1) + trainer._on_start() + + data = _build_raw_batch(B=2, N=4, T=5, F=5) + data = torch_helper.to_device(data, device=trainer._device) + loss_dict = trainer._forward_and_loss(data) + + required_keys = {'loss', 'track_loss', 'det_loss', 'track_labels', 'det_labels', + 'track_predictions', 'det_predictions', 'track_mask', 'det_mask'} + assert required_keys.issubset(set(loss_dict.keys())) + + def test_loss_is_scalar(self): + trainer = _build_e2e_trainer(n_gradient_frames=1) + trainer._on_start() + + data = _build_raw_batch(B=2, N=4, T=5, F=5) + data = torch_helper.to_device(data, device=trainer._device) + loss_dict = trainer._forward_and_loss(data) + + assert loss_dict['loss'].dim() == 0 + + def test_loss_has_grad(self): + trainer = _build_e2e_trainer(n_gradient_frames=1) + trainer._on_start() + + data = _build_raw_batch(B=1, N=3, T=3, F=5) + data = torch_helper.to_device(data, device=trainer._device) + loss_dict = trainer._forward_and_loss(data) + + assert loss_dict['loss'].requires_grad + + def test_with_masking_no_nan(self): + trainer = _build_e2e_trainer(n_gradient_frames=1) + trainer._on_start() + + data = _build_raw_batch_with_masking(B=2, N=4, T=5, F=5) + data = torch_helper.to_device(data, device=trainer._device) + loss_dict = trainer._forward_and_loss(data) + + assert not torch.isnan(loss_dict['loss']) + assert not torch.isinf(loss_dict['loss']) + + def test_backward_succeeds_all_gradient_frames(self): + for n_grad in [1, 2, 3]: + model = _build_small_tdsp() + trainer = _build_e2e_trainer(model=model, n_gradient_frames=n_grad) + trainer._on_start() + + data = _build_raw_batch(B=1, N=3, T=5, F=5) + data = torch_helper.to_device(data, device=trainer._device) + loss_dict = trainer._forward_and_loss(data) + loss_dict['loss'].backward() + + has_grad = any(p.grad is not None for p in model.parameters()) + assert has_grad, f'No gradients with n_gradient_frames={n_grad}' + trainer._optimizer.zero_grad() + + def test_loss_is_finite(self): + trainer = _build_e2e_trainer(n_gradient_frames=2) + trainer._on_start() + + data = _build_raw_batch(B=2, N=4, T=5, F=5) + data = torch_helper.to_device(data, device=trainer._device) + loss_dict = trainer._forward_and_loss(data) + + assert torch.isfinite(loss_dict['loss']) + + +# --- Track State Tests --- + +class TestTrackInitialization: + def test_frame0_init(self): + trainer = _build_e2e_trainer() + state = trainer._init_track_state(B=1, N=3, history_len=5, feature_shapes={'bbox': 5}, device='cpu') + + det_features = {'bbox': torch.rand(1, 3, 5)} + det_mask = torch.tensor([[False, False, True]]) # obj 0,1 present; obj 2 absent + det_ids = torch.tensor([[10, 20, -1]]) + det_ts = torch.tensor([[0, 0, 0]]) + + trainer._initialize_tracks_from_detections(state, det_features, det_mask, det_ids, det_ts) + + assert state.active[0, 0].item() is True + assert state.active[0, 1].item() is True + assert state.active[0, 2].item() is False + assert state.assigned_ids[0, 0].item() == 10 + assert state.assigned_ids[0, 1].item() == 20 + # Data placed at last history position + assert state.mask[0, 0, -1].item() is False + assert state.mask[0, 0, 0].item() is True # earlier positions still masked + + +class TestTrackStateUpdate: + def test_matched_appends_features(self): + trainer = _build_e2e_trainer() + state = trainer._init_track_state(B=1, N=3, history_len=5, feature_shapes={'bbox': 5}, device='cpu') + + # Setup: track 0 active with 1 frame of history + state.active[0, 0] = True + state.raw_features['bbox'][0, 0, -1] = torch.ones(5) + state.mask[0, 0, -1] = False + state.assigned_ids[0, 0] = 10 + + det_features = {'bbox': torch.tensor([[[2.0, 2.0, 2.0, 2.0, 2.0], + [3.0, 3.0, 3.0, 3.0, 3.0], + [0.0, 0.0, 0.0, 0.0, 0.0]]])} + det_mask = torch.tensor([[False, False, True]]) + det_ids = torch.tensor([[10, 20, -1]]) + det_ts = torch.tensor([[1, 1, 1]]) + + associations = [ + ([(0, 0)], [], [1]), # track 0 matched to det 0; det 1 unmatched + ] + + trainer._update_track_state(state, associations, det_features, det_mask, det_ids, det_ts) + + # Track 0 should now have det 0's features at last position + assert torch.allclose(state.raw_features['bbox'][0, 0, -1], torch.tensor([2.0, 2.0, 2.0, 2.0, 2.0])) + assert state.assigned_ids[0, 0].item() == 10 + # Original data should have shifted left + assert state.mask[0, 0, -2].item() is False + + def test_unmatched_det_creates_new_track(self): + trainer = _build_e2e_trainer() + state = trainer._init_track_state(B=1, N=4, history_len=5, feature_shapes={'bbox': 5}, device='cpu') + + state.active[0, 0] = True # only track 0 active + state.assigned_ids[0, 0] = 10 + + det_features = {'bbox': torch.tensor([[[0.0] * 5, [7.0, 7.0, 7.0, 7.0, 7.0], [0.0] * 5, [0.0] * 5]])} + det_mask = torch.tensor([[True, False, True, True]]) # only det 1 present + det_ids = torch.tensor([[-1, 20, -1, -1]]) + det_ts = torch.tensor([[1, 1, 1, 1]]) + + associations = [ + ([], [0], [1]), # track 0 unmatched; det 1 unmatched + ] + + trainer._update_track_state(state, associations, det_features, det_mask, det_ids, det_ts) + + # Det 1 should be assigned to first free slot (slot 1) + assert state.active[0, 1].item() is True + assert state.assigned_ids[0, 1].item() == 20 + assert torch.allclose(state.raw_features['bbox'][0, 1, -1], torch.tensor([7.0, 7.0, 7.0, 7.0, 7.0])) + assert state.mask[0, 1, -1].item() is False + assert state.mask[0, 1, 0].item() is True # rest of history masked + + +# --- Aggregate Loss Dict Tests --- + +class TestAggregateLossDicts: + def test_averages_losses(self): + d1 = { + 'loss': torch.tensor(2.0), + 'track_loss': torch.tensor(1.0), + 'det_loss': torch.tensor(1.0), + 'track_labels': torch.tensor([0, 1]), + 'det_labels': torch.tensor([0, 1]), + 'track_predictions': torch.tensor([0, 0]), + 'det_predictions': torch.tensor([0, 0]), + 'track_mask': None, + 'det_mask': None, + } + d2 = { + 'loss': torch.tensor(4.0), + 'track_loss': torch.tensor(3.0), + 'det_loss': torch.tensor(1.0), + 'track_labels': torch.tensor([2, 3]), + 'det_labels': torch.tensor([2, 3]), + 'track_predictions': torch.tensor([2, 2]), + 'det_predictions': torch.tensor([2, 2]), + 'track_mask': None, + 'det_mask': None, + } + + agg = EndToEndTrainer._aggregate_loss_dicts([d1, d2]) + + assert torch.isclose(agg['loss'], torch.tensor(3.0)) + assert torch.isclose(agg['track_loss'], torch.tensor(2.0)) + assert len(agg['track_labels']) == 4 + assert len(agg['track_predictions']) == 4 + + def test_empty_raises(self): + with pytest.raises(RuntimeError): + EndToEndTrainer._aggregate_loss_dicts([]) + + +# --- GT-association correctness test --- + +class TestGTAssociationCorrectness: + """When every Hungarian match is correct (GT), the E2E track history at the + last frame must equal the GT per-frame features in order. + + Setup: B=1, N=3 objects, T=4 observed frames + 1 unobserved (5 total). + All objects present at all frames with unique IDs. + sim_threshold=1.0 so no matches are rejected. + + After autoregressive processing (5 steps: init + 4 association steps): + - Frame 0 initialises tracks (placed at history[-1]). + - Frames 1..4 shift history left and append at history[-1]. + - With T=4 history slots, after 4 association steps the buffer contains + exactly frames [1, 2, 3, 4] (frame 0 was shifted out). + """ + + def _gt_associations(self, model_output, state, det_mask): + """Return identity matches: track i <-> detection i for all present pairs.""" + B = det_mask.shape[0] + results = [] + for b in range(B): + active = state.active[b].nonzero(as_tuple=True)[0].tolist() + present = (~det_mask[b]).nonzero(as_tuple=True)[0].tolist() + matched_indices = set(active) & set(present) + matches = [(i, i) for i in sorted(matched_indices)] + unmatched_tracks = [i for i in active if i not in matched_indices] + unmatched_dets = [i for i in present if i not in matched_indices] + results.append((matches, unmatched_tracks, unmatched_dets)) + return results + + def test_history_matches_gt_when_associations_are_perfect(self): + B, N, T, F = 1, 3, 4, 5 + torch.manual_seed(42) + + # Build raw batch: all objects present everywhere, unique IDs + raw_features = torch.rand(B, N, T + 1, F) + data = { + 'observed': { + 'features': {'bbox': raw_features[:, :, :T, :]}, + 'mask': torch.zeros(B, N, T, dtype=torch.bool), + 'ids': torch.arange(N).unsqueeze(0).unsqueeze(-1).expand(B, N, T).clone(), + 'ts': torch.arange(T).unsqueeze(0).unsqueeze(0).expand(B, N, T).clone(), + }, + 'unobserved': { + 'features': {'bbox': raw_features[:, :, T, :]}, + 'mask': torch.zeros(B, N, dtype=torch.bool), + 'ids': torch.arange(N).unsqueeze(0).expand(B, N).clone(), + 'ts': torch.full((B, N), T, dtype=torch.long), + } + } + + trainer = _build_e2e_trainer(n_gradient_frames=1) + trainer._on_start() + + data = torch_helper.to_device(data, device=trainer._device) + + # Patch _compute_associations to return GT (identity) matches + with patch.object(trainer, '_compute_associations', side_effect=self._gt_associations): + _, state = trainer._forward_and_loss(data, return_state=True) + + # After T association steps with T history slots, history contains + # frames [1, 2, 3, 4] (frame 0 shifted out). + expected = raw_features[:, :, 1:, :] # (B, N, T, F) = frames 1..T + actual = state.raw_features['bbox'] + + for i in range(N): + assert state.active[0, i].item() is True, f'Track {i} should be active' + assert state.assigned_ids[0, i].item() == i, f'Track {i} ID should be {i}' + assert torch.allclose(actual[0, i], expected[0, i], atol=1e-6), \ + f'Track {i} history does not match GT frames [1..{T}]' + assert not state.mask[0, i].any(), f'Track {i} should have no masked slots' diff --git a/tests/test_trainer_refactor.py b/tests/test_trainer_refactor.py new file mode 100644 index 0000000..a59d8e4 --- /dev/null +++ b/tests/test_trainer_refactor.py @@ -0,0 +1,115 @@ +"""Tests that the _compute_model_output_and_loss refactor doesn't break ContrastiveTrainer.""" +import torch + +from tdlp.architectures.tdlp.core import build_mm_tdsp_model +from tdlp.trainer.losses.bce import ClipLevelBCE +from tdlp.trainer.trainer import ContrastiveTrainer +from tdlp.trainer import torch_helper + + +def _build_small_tdsp(): + # input_dim=5: model splits 10D input into 5D static + 5D motion + return build_mm_tdsp_model( + per_feature_params={'bbox': { + 'feature_encoder_type': 'motion', + 'feature_encoder_params': {'input_dim': 5}, + }}, + common_params={ + 'hidden_dim': 16, 'dropout': 0.0, + 'track_encoder_n_heads': 2, 'track_encoder_n_layers': 1, + 'track_encoder_ffn_dim': 32, 'projector_intermediate_dim': 16, + }, + sph_per_feature_params={'bbox': {'hidden_dim': 16}}, + sph_common_params={'hidden_dim': 16}, + mm_dim=16, + similarity_prediction_head_hidden_dim=16, + similarity_head_type='compact_mlp', + aggregator_type='sum', + aggregator_params={}, + ) + + +def _build_transformed_batch(B=2, N=4, T=5): + """Build a batch that looks like post-transform data. + + Observed features are 10D (5 coords + 5 FoD). + Unobserved features are 5D (standardized only, no FoD for detections). + """ + return { + 'observed': { + 'features': {'bbox': torch.randn(B, N, T, 10)}, + 'mask': torch.zeros(B, N, T, dtype=torch.bool), + 'ids': torch.arange(N).unsqueeze(0).unsqueeze(-1).expand(B, N, T).clone(), + 'ts': torch.arange(T).unsqueeze(0).unsqueeze(0).expand(B, N, T).clone(), + }, + 'unobserved': { + 'features': {'bbox': torch.randn(B, N, 5)}, + 'mask': torch.zeros(B, N, dtype=torch.bool), + 'ids': torch.arange(N).unsqueeze(0).expand(B, N).clone(), + 'ts': torch.full((B, N), T, dtype=torch.long), + } + } + + +def _build_trainer(model, loss_fn): + optimizer = torch.optim.Adam(model.parameters(), lr=1e-3) + scheduler = torch.optim.lr_scheduler.ConstantLR(optimizer, factor=1.0) + return ContrastiveTrainer( + model=model, + loss_func=loss_fn, + optimizer=optimizer, + scheduler=scheduler, + n_epochs=1, + tensorboard_log_dirpath='/tmp/test_tb', + checkpoints_dirpath='/tmp/test_ckpt', + device='cpu', + ) + + +def test_compute_model_output_and_loss_returns_model_output(): + model = _build_small_tdsp() + loss_fn = ClipLevelBCE() + trainer = _build_trainer(model, loss_fn) + trainer._on_start() + + data = _build_transformed_batch() + data = torch_helper.to_device(data, device=trainer._device) + + loss_dict, model_output = trainer._compute_model_output_and_loss( + data['observed']['features'], data['observed']['mask'], data['observed']['ids'], + data['unobserved']['features'], data['unobserved']['mask'], data['unobserved']['ids'] + ) + + assert 'loss' in loss_dict + assert model_output is not None + + +def test_forward_and_loss_returns_loss_with_grad(): + model = _build_small_tdsp() + loss_fn = ClipLevelBCE() + trainer = _build_trainer(model, loss_fn) + trainer._on_start() + + torch.manual_seed(42) + data = _build_transformed_batch() + data = torch_helper.to_device(data, device=trainer._device) + + loss_dict = trainer._forward_and_loss(data) + assert 'loss' in loss_dict + assert loss_dict['loss'].requires_grad + + +def test_forward_and_loss_backward_succeeds(): + model = _build_small_tdsp() + loss_fn = ClipLevelBCE() + trainer = _build_trainer(model, loss_fn) + trainer._on_start() + + data = _build_transformed_batch() + data = torch_helper.to_device(data, device=trainer._device) + + loss_dict = trainer._forward_and_loss(data) + loss_dict['loss'].backward() + + has_grad = any(p.grad is not None for p in model.parameters()) + assert has_grad diff --git a/tools/inference.py b/tools/inference.py index ddfe4b8..12dba5c 100755 --- a/tools/inference.py +++ b/tools/inference.py @@ -4,7 +4,7 @@ import time import hydra -from motrack.evaluation.io import TrackerInferenceWriter +from motrack.inference.io import TrackerInferenceWriter from motrack.object_detection import DetectionManager from motrack.tools.postprocess import run_tracker_postprocess from motrack.tools.visualize import run_visualize_tracker_inference diff --git a/tools/motrack_eval.py b/tools/motrack_eval.py new file mode 100644 index 0000000..a100d36 --- /dev/null +++ b/tools/motrack_eval.py @@ -0,0 +1,29 @@ +"""TDLP tracker evaluation using Motrack's eval pipeline. + +Run after ``tools/motrack_inference.py`` to compute HOTA / IDF1 / MOTA on +the inference outputs and log a run to MLflow (when ``cfg.mlflow.enabled``). +""" +import os + +import hydra + +# Side-effects: register 'tdlp' in TRACKER_CATALOG and 'tdlp_dancetrack' in DATASET_CATALOG +import tdlp.tracker # noqa: F401 +import tdlp.datasets # noqa: F401 + +from motrack.config_parser import GlobalConfig +from motrack.tools import run_eval +from motrack.tools.mlflow_logger import load_and_log_run +from motrack.utils import pipeline +from tdlp.common.project import MOTRACK_CONFIGS_PATH + + +@hydra.main(config_path=os.path.join(MOTRACK_CONFIGS_PATH, 'dancetrack'), config_name='tdlp_infer', version_base='1.1') +@pipeline.task('motrack-eval') +def main(cfg: GlobalConfig) -> None: + run_eval(cfg) + load_and_log_run(cfg) + + +if __name__ == '__main__': + main() diff --git a/tools/motrack_inference.py b/tools/motrack_inference.py new file mode 100644 index 0000000..f31b312 --- /dev/null +++ b/tools/motrack_inference.py @@ -0,0 +1,23 @@ +"""TDLP tracker inference using Motrack's inference pipeline.""" +import os + +import hydra + +# Side-effects: register 'tdlp' in TRACKER_CATALOG and 'tdlp_dancetrack' in DATASET_CATALOG +import tdlp.tracker # noqa: F401 +import tdlp.datasets # noqa: F401 + +from motrack.config_parser import GlobalConfig +from motrack.tools import run_inference +from motrack.utils import pipeline +from tdlp.common.project import MOTRACK_CONFIGS_PATH + + +@hydra.main(config_path=os.path.join(MOTRACK_CONFIGS_PATH, 'dancetrack'), config_name='tdlp_infer', version_base='1.1') +@pipeline.task('motrack-inference') +def main(cfg: GlobalConfig) -> None: + run_inference(cfg) + + +if __name__ == '__main__': + main() diff --git a/tools/motrack_optimize.py b/tools/motrack_optimize.py new file mode 100644 index 0000000..0cefd9e --- /dev/null +++ b/tools/motrack_optimize.py @@ -0,0 +1,23 @@ +"""TDLP tracker hyperparameter optimization using Motrack's optimization core.""" +import os + +import hydra + +# Side-effects: register 'tdlp' in TRACKER_CATALOG and 'tdlp_dancetrack' in DATASET_CATALOG +import tdlp.tracker # noqa: F401 +import tdlp.datasets # noqa: F401 + +from motrack.config_parser import GlobalConfig +from motrack.tools import run_optimize +from motrack.utils import pipeline +from tdlp.common.project import MOTRACK_CONFIGS_PATH + + +@hydra.main(config_path=os.path.join(MOTRACK_CONFIGS_PATH, 'dancetrack'), config_name='tpe_tdlp', version_base='1.1') +@pipeline.task('motrack-optimize') +def main(cfg: GlobalConfig) -> None: + run_optimize(cfg) + + +if __name__ == '__main__': + main() diff --git a/tools/train.py b/tools/train.py index b389b09..f5e8b67 100644 --- a/tools/train.py +++ b/tools/train.py @@ -6,8 +6,9 @@ from tdlp.common.project import CONFIGS_PATH from tdlp.config_parser import GlobalConfig from tdlp.datasets.dataset import MOTClipDataset, dataset_index_factory +from tdlp.trainer.factory import build_trainer from tdlp.trainer.torch_distrib_utils import DistributedSamplerWrapper -from tdlp.trainer.trainer import ContrastiveTrainer +from tdlp.trainer.types import TrainerType from tdlp.utils import pipeline from tools.utils import check_train_experiment_history, logger import torch @@ -72,6 +73,9 @@ def main(cfg: GlobalConfig) -> None: experiment_name=cfg.experiment_name ) + trainer_type = TrainerType(cfg.train.trainer_type) + is_e2e = trainer_type == TrainerType.END_TO_END + train_index = dataset_index_factory( name=cfg.dataset.index.type, params=cfg.dataset.index.params, @@ -79,7 +83,7 @@ def main(cfg: GlobalConfig) -> None: sequence_list=cfg.dataset.index.sequence_list ) - train_dataset = cfg.dataset.build_dataset(train_index) + train_dataset = cfg.dataset.build_dataset(train_index, disable_transform=is_e2e) train_sampler = cfg.dataset.build_sampler(train_dataset) @@ -99,7 +103,7 @@ def main(cfg: GlobalConfig) -> None: sequence_list=cfg.dataset.index.sequence_list, ) - val_dataset = cfg.dataset.build_dataset(val_index) + val_dataset = cfg.dataset.build_dataset(val_index, disable_transform=is_e2e) val_dataloader = create_dataloader( val_dataset, @@ -128,20 +132,24 @@ def main(cfg: GlobalConfig) -> None: tensorboard_log_dirpath = \ conventions.get_tensorboard_logs_dirpath(cfg.path.master, cfg.dataset_name, cfg.experiment_name) checkpoints_dirpath = conventions.get_checkpoints_dirpath(experiment_path) - trainer = ContrastiveTrainer( + + transform = cfg.dataset.build_transform() if is_e2e else None + + trainer = build_trainer( + trainer_type=trainer_type, + trainer_params=cfg.train.trainer_params, model=model, loss_func=loss_func, optimizer=optimizer, scheduler=scheduler, - n_epochs=cfg.train.max_epochs, gradient_clip=cfg.train.gradient_clip, mixed_precision=cfg.train.mixed_precision, device=cfg.resources.accelerator, - tensorboard_log_dirpath=tensorboard_log_dirpath, checkpoints_dirpath=checkpoints_dirpath, - metric_monitor=cfg.train.checkpoint_cfg.metric_monitor + metric_monitor=cfg.train.checkpoint_cfg.metric_monitor, + transform=transform, ) if checkpoint_path is not None: diff --git a/uv.lock b/uv.lock index a976ba6..0755ad7 100644 --- a/uv.lock +++ b/uv.lock @@ -27,6 +27,80 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/00/b08f23b7d7e1e14ce01419a467b583edbb93c6cdb8654e54a9cc579cd61f/addict-2.4.0-py3-none-any.whl", hash = "sha256:249bb56bbfd3cdc2a004ea0ff4c2b6ddc84d53bc2194761636eb314d5cfa5dfc", size = 3832, upload-time = "2020-11-21T16:21:29.588Z" }, ] +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.13.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs", marker = "sys_platform == 'linux'" }, + { name = "aiosignal", marker = "sys_platform == 'linux'" }, + { name = "attrs", marker = "sys_platform == 'linux'" }, + { name = "frozenlist", marker = "sys_platform == 'linux'" }, + { name = "multidict", marker = "sys_platform == 'linux'" }, + { name = "propcache", marker = "sys_platform == 'linux'" }, + { name = "yarl", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/ba/3bc7525d7e2beaa11b309a70d48b0d3cfc3c2089ec6a7d0820d59c657053/aiohttp-3.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2567b72e1ffc3ab25510db43f355b29eeada56c0a622e58dcdb19530eb0a3cb", size = 1763757, upload-time = "2026-03-31T21:57:07.882Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ab/e87744cf18f1bd78263aba24924d4953b41086bd3a31d22452378e9028a0/aiohttp-3.13.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fb0540c854ac9c0c5ad495908fdfd3e332d553ec731698c0e29b1877ba0d2ec6", size = 1720152, upload-time = "2026-03-31T21:57:09.946Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f3/ed17a6f2d742af17b50bae2d152315ed1b164b07a5fd5cc1754d99e4dfa5/aiohttp-3.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9883051c6972f58bfc4ebb2116345ee2aa151178e99c3f2b2bbe2af712abd13", size = 1818010, upload-time = "2026-03-31T21:57:12.157Z" }, + { url = "https://files.pythonhosted.org/packages/53/06/ecbc63dc937192e2a5cb46df4d3edb21deb8225535818802f210a6ea5816/aiohttp-3.13.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2294172ce08a82fb7c7273485895de1fa1186cc8294cfeb6aef4af42ad261174", size = 1907251, upload-time = "2026-03-31T21:57:14.023Z" }, + { url = "https://files.pythonhosted.org/packages/7e/a5/0521aa32c1ddf3aa1e71dcc466be0b7db2771907a13f18cddaa45967d97b/aiohttp-3.13.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3a807cabd5115fb55af198b98178997a5e0e57dead43eb74a93d9c07d6d4a7dc", size = 1759969, upload-time = "2026-03-31T21:57:16.146Z" }, + { url = "https://files.pythonhosted.org/packages/f6/78/a38f8c9105199dd3b9706745865a8a59d0041b6be0ca0cc4b2ccf1bab374/aiohttp-3.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aa6d0d932e0f39c02b80744273cd5c388a2d9bc07760a03164f229c8e02662f6", size = 1616871, upload-time = "2026-03-31T21:57:17.856Z" }, + { url = "https://files.pythonhosted.org/packages/6f/41/27392a61ead8ab38072105c71aa44ff891e71653fe53d576a7067da2b4e8/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60869c7ac4aaabe7110f26499f3e6e5696eae98144735b12a9c3d9eae2b51a49", size = 1739844, upload-time = "2026-03-31T21:57:19.679Z" }, + { url = "https://files.pythonhosted.org/packages/6e/55/5564e7ae26d94f3214250009a0b1c65a0c6af4bf88924ccb6fdab901de28/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:26d2f8546f1dfa75efa50c3488215a903c0168d253b75fba4210f57ab77a0fb8", size = 1731969, upload-time = "2026-03-31T21:57:22.006Z" }, + { url = "https://files.pythonhosted.org/packages/6d/c5/705a3929149865fc941bcbdd1047b238e4a72bcb215a9b16b9d7a2e8d992/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1162a1492032c82f14271e831c8f4b49f2b6078f4f5fc74de2c912fa225d51d", size = 1795193, upload-time = "2026-03-31T21:57:24.256Z" }, + { url = "https://files.pythonhosted.org/packages/a6/19/edabed62f718d02cff7231ca0db4ef1c72504235bc467f7b67adb1679f48/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8b14eb3262fad0dc2f89c1a43b13727e709504972186ff6a99a3ecaa77102b6c", size = 1606477, upload-time = "2026-03-31T21:57:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/de/fc/76f80ef008675637d88d0b21584596dc27410a990b0918cb1e5776545b5b/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ca9ac61ac6db4eb6c2a0cd1d0f7e1357647b638ccc92f7e9d8d133e71ed3c6ac", size = 1813198, upload-time = "2026-03-31T21:57:28.316Z" }, + { url = "https://files.pythonhosted.org/packages/e5/67/5b3ac26b80adb20ea541c487f73730dc8fa107d632c998f25bbbab98fcda/aiohttp-3.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7996023b2ed59489ae4762256c8516df9820f751cf2c5da8ed2fb20ee50abab3", size = 1752321, upload-time = "2026-03-31T21:57:30.549Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + +[[package]] +name = "alembic" +version = "1.18.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mako", marker = "sys_platform == 'linux'" }, + { name = "sqlalchemy", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/13/8b084e0f2efb0275a1d534838844926f798bd766566b1375174e2448cd31/alembic-1.18.4.tar.gz", hash = "sha256:cb6e1fd84b6174ab8dbb2329f86d631ba9559dd78df550b57804d607672cedbc", size = 2056725, upload-time = "2026-02-10T16:00:47.195Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/29/6533c317b74f707ea28f8d633734dbda2119bbadfc61b2f3640ba835d0f7/alembic-1.18.4-py3-none-any.whl", hash = "sha256:a5ed4adcf6d8a4cb575f3d759f071b03cd6e5c7618eb796cb52497be25bfe19a", size = 263893, upload-time = "2026-02-10T16:00:49.997Z" }, +] + +[[package]] +name = "annotated-doc" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, +] + [[package]] name = "annotated-types" version = "0.7.0" @@ -64,6 +138,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ce/66/686ac4fc6ef48f5bacde625adac698f41d5316a9753c2b20bb0931c9d4e2/astroid-4.0.3-py3-none-any.whl", hash = "sha256:864a0a34af1bd70e1049ba1e61cee843a7252c826d97825fcee9b2fcbd9e1b14", size = 276443, upload-time = "2026-01-03T22:14:24.412Z" }, ] +[[package]] +name = "attrs" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, +] + +[[package]] +name = "blinker" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, +] + +[[package]] +name = "cachetools" +version = "7.0.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/7b/1755ed2c6bfabd1d98b37ae73152f8dcf94aa40fee119d163c19ed484704/cachetools-7.0.6.tar.gz", hash = "sha256:e5d524d36d65703a87243a26ff08ad84f73352adbeafb1cde81e207b456aaf24", size = 37526, upload-time = "2026-04-20T19:02:23.289Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/c4/cf76242a5da1410917107ff14551764aa405a5fd10cd10cf9a5ca8fa77f4/cachetools-7.0.6-py3-none-any.whl", hash = "sha256:4e94956cfdd3086f12042cdd29318f5ced3893014f7d0d059bf3ead3f85b7f8b", size = 13976, upload-time = "2026-04-20T19:02:21.187Z" }, +] + [[package]] name = "certifi" version = "2026.1.4" @@ -73,6 +174,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, ] +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy' and sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, +] + [[package]] name = "charset-normalizer" version = "3.4.6" @@ -103,6 +223,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, ] +[[package]] +name = "cloudpickle" +version = "3.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330, upload-time = "2025-11-03T09:25:26.604Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228, upload-time = "2025-11-03T09:25:25.534Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -112,6 +241,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "colorlog" +version = "6.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, +] + [[package]] name = "contourpy" version = "1.3.2" @@ -130,6 +268,43 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d4/79/6be7e90c955c0487e7712660d6cead01fa17bff98e0ea275737cc2bc8e71/contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5", size = 318729, upload-time = "2025-04-15T17:45:20.166Z" }, ] +[[package]] +name = "cryptography" +version = "46.0.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" }, + { url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" }, + { url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" }, + { url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" }, + { url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" }, + { url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" }, + { url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" }, + { url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" }, + { url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" }, + { url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" }, + { url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" }, + { url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" }, + { url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" }, + { url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" }, + { url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" }, + { url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" }, + { url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" }, + { url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" }, + { url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" }, + { url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" }, + { url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ea/075aac6a84b7c271578d81a2f9968acb6e273002408729f2ddff517fed4a/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d3b99c535a9de0adced13d159c5a9cf65c325601aa30f4be08afd680643e9c15", size = 4219700, upload-time = "2026-04-08T01:57:40.625Z" }, + { url = "https://files.pythonhosted.org/packages/6c/7b/1c55db7242b5e5612b29fc7a630e91ee7a6e3c8e7bf5406d22e206875fbd/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d02c738dacda7dc2a74d1b2b3177042009d5cab7c7079db74afc19e56ca1b455", size = 4385982, upload-time = "2026-04-08T01:57:42.725Z" }, + { url = "https://files.pythonhosted.org/packages/cb/da/9870eec4b69c63ef5925bf7d8342b7e13bc2ee3d47791461c4e49ca212f4/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:04959522f938493042d595a736e7dbdff6eb6cc2339c11465b3ff89343b65f65", size = 4219115, upload-time = "2026-04-08T01:57:44.939Z" }, + { url = "https://files.pythonhosted.org/packages/f4/72/05aa5832b82dd341969e9a734d1812a6aadb088d9eb6f0430fc337cc5a8f/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3986ac1dee6def53797289999eabe84798ad7817f3e97779b5061a95b0ee4968", size = 4385479, upload-time = "2026-04-08T01:57:46.86Z" }, +] + [[package]] name = "cycler" version = "0.12.1" @@ -148,6 +323,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" }, ] +[[package]] +name = "databricks-sdk" +version = "0.106.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth", marker = "sys_platform == 'linux'" }, + { name = "protobuf", marker = "sys_platform == 'linux'" }, + { name = "requests", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b5/b7/ef86e7b8c3d135c844f972e06efb628e147eed0a7b9a0ecbf9511437a3c2/databricks_sdk-0.106.0.tar.gz", hash = "sha256:6bbd492cb8593747aced037b9186f8632e9d553fc358e6f3d83b7e959851d9d3", size = 930953, upload-time = "2026-04-30T12:33:19.601Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/a9/63b4f6ef3078e4d060faaad85c4e43667189c3429edd68d5cbddc45187ca/databricks_sdk-0.106.0-py3-none-any.whl", hash = "sha256:db9de5566279ae80dfea0ecd37231e8968523ef984e83cbe4bd77e50c59aa6a5", size = 879452, upload-time = "2026-04-30T12:33:18.116Z" }, +] + [[package]] name = "dill" version = "0.4.0" @@ -157,6 +346,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, ] +[[package]] +name = "docker" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests", marker = "sys_platform == 'linux'" }, + { name = "urllib3", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/9b/4a2ea29aeba62471211598dac5d96825bb49348fa07e906ea930394a83ce/docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", size = 117834, upload-time = "2024-05-23T11:13:57.216Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/26/57c6fb270950d476074c087527a558ccb6f4436657314bfb6cdf484114c4/docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0", size = 147774, upload-time = "2024-05-23T11:13:55.01Z" }, +] + [[package]] name = "einops" version = "0.8.1" @@ -166,6 +368,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl", hash = "sha256:919387eb55330f5757c6bea9165c5ff5cfe63a642682ea788a6d472576d81737", size = 64359, upload-time = "2025-02-09T03:17:01.998Z" }, ] +[[package]] +name = "fastapi" +version = "0.136.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc", marker = "sys_platform == 'linux'" }, + { name = "pydantic", marker = "sys_platform == 'linux'" }, + { name = "starlette", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, + { name = "typing-inspection", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5d/45/c130091c2dfa061bbfe3150f2a5091ef1adf149f2a8d2ae769ecaf6e99a2/fastapi-0.136.1.tar.gz", hash = "sha256:7af665ad7acfa0a3baf8983d393b6b471b9da10ede59c60045f49fbc89a0fa7f", size = 397448, upload-time = "2026-04-23T16:49:44.046Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/ff/2e4eca3ade2c22fe1dea7043b8ee9dabe47753349eb1b56a202de8af6349/fastapi-0.136.1-py3-none-any.whl", hash = "sha256:a6e9d7eeada96c93a4d69cb03836b44fa34e2854accb7244a1ece36cd4781c3f", size = 117683, upload-time = "2026-04-23T16:49:42.437Z" }, +] + [[package]] name = "filelock" version = "3.18.0" @@ -175,6 +393,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, ] +[[package]] +name = "flask" +version = "3.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "blinker", marker = "sys_platform == 'linux'" }, + { name = "click", marker = "sys_platform == 'linux'" }, + { name = "itsdangerous", marker = "sys_platform == 'linux'" }, + { name = "jinja2", marker = "sys_platform == 'linux'" }, + { name = "markupsafe", marker = "sys_platform == 'linux'" }, + { name = "werkzeug", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/26/00/35d85dcce6c57fdc871f3867d465d780f302a175ea360f62533f12b27e2b/flask-3.1.3.tar.gz", hash = "sha256:0ef0e52b8a9cd932855379197dd8f94047b359ca0a78695144304cb45f87c9eb", size = 759004, upload-time = "2026-02-19T05:00:57.678Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl", hash = "sha256:f4bcbefc124291925f1a26446da31a5178f9483862233b23c0c96a20701f670c", size = 103424, upload-time = "2026-02-19T05:00:56.027Z" }, +] + +[[package]] +name = "flask-cors" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flask", marker = "sys_platform == 'linux'" }, + { name = "werkzeug", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/74/0fc0fa68d62f21daef41017dafab19ef4b36551521260987eb3a5394c7ba/flask_cors-6.0.2.tar.gz", hash = "sha256:6e118f3698249ae33e429760db98ce032a8bf9913638d085ca0f4c5534ad2423", size = 13472, upload-time = "2025-12-12T20:31:42.861Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/af/72ad54402e599152de6d067324c46fe6a4f531c7c65baf7e96c63db55eaf/flask_cors-6.0.2-py3-none-any.whl", hash = "sha256:e57544d415dfd7da89a9564e1e3a9e515042df76e12130641ca6f3f2f03b699a", size = 13257, upload-time = "2025-12-12T20:31:41.3Z" }, +] + [[package]] name = "fonttools" version = "4.58.4" @@ -188,6 +436,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0b/2f/c536b5b9bb3c071e91d536a4d11f969e911dbb6b227939f4c5b0bca090df/fonttools-4.58.4-py3-none-any.whl", hash = "sha256:a10ce13a13f26cbb9f37512a4346bb437ad7e002ff6fa966a7ce7ff5ac3528bd", size = 1114660, upload-time = "2025-06-13T17:25:13.321Z" }, ] +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" }, + { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" }, + { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" }, + { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" }, + { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" }, + { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" }, + { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, +] + [[package]] name = "fsspec" version = "2025.5.1" @@ -197,6 +464,94 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bb/61/78c7b3851add1481b048b5fdc29067397a1784e2910592bc81bb3f608635/fsspec-2025.5.1-py3-none-any.whl", hash = "sha256:24d3a2e663d5fc735ab256263c4075f374a174c3410c0b25e5bd1970bceaa462", size = 199052, upload-time = "2025-05-24T12:03:21.66Z" }, ] +[[package]] +name = "gitdb" +version = "4.0.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "smmap", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, +] + +[[package]] +name = "gitpython" +version = "3.1.49" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "gitdb", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/63/210aaa302d6a0a78daa67c5c15bbac2cad361722841278b0209b6da20855/gitpython-3.1.49.tar.gz", hash = "sha256:42f9399c9eb33fc581014bedd76049dfbaf6375aa2a5754575966387280315e1", size = 219367, upload-time = "2026-04-29T00:31:20.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/6f/b842bfa6f21d6f87c57f9abf7194225e55279d96d869775e19e9f7236fc5/gitpython-3.1.49-py3-none-any.whl", hash = "sha256:024b0422d7f84d15cd794844e029ffebd4c5d42a7eb9b936b458697ef550a02c", size = 212190, upload-time = "2026-04-29T00:31:18.412Z" }, +] + +[[package]] +name = "google-auth" +version = "2.50.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography", marker = "sys_platform == 'linux'" }, + { name = "pyasn1-modules", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5f/18/238d7021d151bdab868f23433817b027dd759135202f4dfce0670d1230ca/google_auth-2.50.0.tar.gz", hash = "sha256:f35eafb191195328e8ce10a7883970877e7aeb49c2bfaa54aa0e394316d353d0", size = 336523, upload-time = "2026-04-30T21:19:29.659Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/cf/4880c2137c14280b2f59975cdf12cc442bc0ae1f9ea473a26eaa0c146786/google_auth-2.50.0-py3-none-any.whl", hash = "sha256:04382175e28b94f49694977f0a792688b59a668def1499e9d8de996dc9ce5b15", size = 246495, upload-time = "2026-04-30T21:19:27.664Z" }, +] + +[[package]] +name = "graphene" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "graphql-core", marker = "sys_platform == 'linux'" }, + { name = "graphql-relay", marker = "sys_platform == 'linux'" }, + { name = "python-dateutil", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cc/f6/bf62ff950c317ed03e77f3f6ddd7e34aaa98fe89d79ebd660c55343d8054/graphene-3.4.3.tar.gz", hash = "sha256:2a3786948ce75fe7e078443d37f609cbe5bb36ad8d6b828740ad3b95ed1a0aaa", size = 44739, upload-time = "2024-11-09T20:44:25.757Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/e0/61d8e98007182e6b2aca7cf65904721fb2e4bce0192272ab9cb6f69d8812/graphene-3.4.3-py2.py3-none-any.whl", hash = "sha256:820db6289754c181007a150db1f7fff544b94142b556d12e3ebc777a7bf36c71", size = 114894, upload-time = "2024-11-09T20:44:23.851Z" }, +] + +[[package]] +name = "graphql-core" +version = "3.2.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/c5/36aa96205c3ecbb3d34c7c24189e4553c7ca2ebc7e1dd07432339b980272/graphql_core-3.2.8.tar.gz", hash = "sha256:015457da5d996c924ddf57a43f4e959b0b94fb695b85ed4c29446e508ed65cf3", size = 513181, upload-time = "2026-03-05T19:55:37.332Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/41/cb887d9afc5dabd78feefe6ccbaf83ff423c206a7a1b7aeeac05120b2125/graphql_core-3.2.8-py3-none-any.whl", hash = "sha256:cbee07bee1b3ed5e531723685369039f32ff815ef60166686e0162f540f1520c", size = 207349, upload-time = "2026-03-05T19:55:35.911Z" }, +] + +[[package]] +name = "graphql-relay" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "graphql-core", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/13/98fbf8d67552f102488ffc16c6f559ce71ea15f6294728d33928ab5ff14d/graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c", size = 50027, upload-time = "2022-04-16T11:03:45.447Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl", hash = "sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5", size = 16940, upload-time = "2022-04-16T11:03:43.895Z" }, +] + +[[package]] +name = "greenlet" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3c/3f/dbf99fb14bfeb88c28f16729215478c0e265cacd6dc22270c8f31bb6892f/greenlet-3.5.0.tar.gz", hash = "sha256:d419647372241bc68e957bf38d5c1f98852155e4146bd1e4121adea81f4f01e4", size = 196995, upload-time = "2026-04-27T13:37:15.544Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/82/800646c7ffc5dbabd75ddd2f6b519bb898c0c9c969e5d0473bfe5d20bcce/greenlet-3.5.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:362624e6a8e5bca3b8233e45eef33903a100e9539a2b995c364d595dbc4018b3", size = 604264, upload-time = "2026-04-27T12:52:39.494Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ac/354867c0bba812fc33b15bc55aedafedd0aee3c7dd91dfca22444157dc0c/greenlet-3.5.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5ecd83806b0f4c2f53b1018e0005cd82269ea01d42befc0368730028d850ed1c", size = 616099, upload-time = "2026-04-27T12:59:39.623Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ab/192090c4a5b30df148c22bf4b8895457d739a7c7c5a7b9c41e5dd7f537f2/greenlet-3.5.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fa94cb2288681e3a11645958f1871d48ee9211bd2f66628fdace505927d6e564", size = 623976, upload-time = "2026-04-27T13:02:37.363Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b0/815bece7399e01cadb69014219eebd0042339875c59a59b0820a46ece356/greenlet-3.5.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ff251e9a0279522e62f6176412869395a64ddf2b5c5f782ff609a8216a4e662", size = 615198, upload-time = "2026-04-27T12:25:25.928Z" }, + { url = "https://files.pythonhosted.org/packages/24/11/05eb2b9b188c6df7d68a89c99134d644a7af616a40b9808e8e6ced315d5d/greenlet-3.5.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:64d6ac45f7271f48e45f67c95b54ef73534c52ec041fcda8edf520c6d811f4bc", size = 418379, upload-time = "2026-04-27T13:05:12.755Z" }, + { url = "https://files.pythonhosted.org/packages/10/80/3b2c0a895d6698f6ddb31b07942ebfa982f3e30888bc5546a5b5990de8b2/greenlet-3.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d874e79afd41a96e11ff4c5d0bc90a80973e476fda1c2c64985667397df432b", size = 1574927, upload-time = "2026-04-27T12:53:25.81Z" }, + { url = "https://files.pythonhosted.org/packages/44/0e/f354af514a4c61454dbc68e44d47544a5a4d6317e30b77ddfa3a09f4c5f3/greenlet-3.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0ed006e4b86c59de7467eb2601cd1b77b5a7d657d1ee55e30fe30d76451edba4", size = 1642683, upload-time = "2026-04-27T12:25:23.9Z" }, +] + [[package]] name = "grpcio" version = "1.73.1" @@ -212,6 +567,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/42/72/a13ff7ba6c68ccffa35dacdc06373a76c0008fd75777cba84d7491956620/grpcio-1.73.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:610e19b04f452ba6f402ac9aa94eb3d21fbc94553368008af634812c4a85a99e", size = 6308380, upload-time = "2025-06-26T01:52:18.417Z" }, ] +[[package]] +name = "gunicorn" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/f4/e78fa054248fab913e2eab0332c6c2cb07421fca1ce56d8fe43b6aef57a4/gunicorn-25.3.0.tar.gz", hash = "sha256:f74e1b2f9f76f6cd1ca01198968bd2dd65830edc24b6e8e4d78de8320e2fe889", size = 634883, upload-time = "2026-03-27T00:00:26.092Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/c8/8aaf447698c4d59aa853fd318eed300b5c9e44459f242ab8ead6c9c09792/gunicorn-25.3.0-py3-none-any.whl", hash = "sha256:cacea387dab08cd6776501621c295a904fe8e3b7aae9a1a3cbb26f4e7ed54660", size = 208403, upload-time = "2026-03-27T00:00:27.386Z" }, +] + [[package]] name = "h11" version = "0.16.0" @@ -261,6 +628,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] +[[package]] +name = "huey" +version = "2.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/29/3428d52eb8e85025e264a291641a9f9d6407cc1e51d1b630f6ac5815999a/huey-2.6.0.tar.gz", hash = "sha256:8d11f8688999d65266af1425b831f6e3773e99415027177b8734b0ffd5e251f6", size = 221068, upload-time = "2026-01-06T03:01:02.055Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/34/fae9ac8f1c3a552fd3f7ff652b94c78d219dedc5fce0c0a4232457760a00/huey-2.6.0-py3-none-any.whl", hash = "sha256:1b9df9d370b49c6d5721ba8a01ac9a787cf86b3bdc584e4679de27b920395c3f", size = 76951, upload-time = "2026-01-06T03:01:00.808Z" }, +] + [[package]] name = "huggingface-hub" version = "1.3.1" @@ -305,6 +681,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] +[[package]] +name = "importlib-metadata" +version = "8.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, +] + [[package]] name = "iniconfig" version = "2.1.0" @@ -323,6 +711,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7f/ed/e3705d6d02b4f7aea715a353c8ce193efd0b5db13e204df895d38734c244/isort-7.0.0-py3-none-any.whl", hash = "sha256:1bcabac8bc3c36c7fb7b98a76c8abb18e0f841a3ba81decac7691008592499c1", size = 94672, upload-time = "2025-10-11T13:30:57.665Z" }, ] +[[package]] +name = "itsdangerous" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, +] + [[package]] name = "jinja2" version = "3.1.6" @@ -362,6 +759,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c9/4f/15988966ba46bcd5ab9d0c8296914436720dd67fca689ae1a75b4ec1c72f/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d47cfb2650f0e103d4bf68b0b5804c68da97272c84bb12850d877a95c056bd67", size = 2312306, upload-time = "2024-12-24T18:29:12.644Z" }, ] +[[package]] +name = "mako" +version = "1.3.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/62/791b31e69ae182791ec67f04850f2f062716bbd205483d63a215f3e062d3/mako-1.3.12.tar.gz", hash = "sha256:9f778e93289bd410bb35daadeb4fc66d95a746f0b75777b942088b7fd7af550a", size = 400219, upload-time = "2026-04-28T19:01:08.512Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/b1/a0ec7a5a9db730a08daef1fdfb8090435b82465abbf758a596f0ea88727e/mako-1.3.12-py3-none-any.whl", hash = "sha256:8f61569480282dbf557145ce441e4ba888be453c30989f879f0d652e39f53ea9", size = 78521, upload-time = "2026-04-28T19:01:10.393Z" }, +] + [[package]] name = "markdown" version = "3.8.2" @@ -437,6 +846,85 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] +[[package]] +name = "mlflow" +version = "3.11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp", marker = "sys_platform == 'linux'" }, + { name = "alembic", marker = "sys_platform == 'linux'" }, + { name = "cryptography", marker = "sys_platform == 'linux'" }, + { name = "docker", marker = "sys_platform == 'linux'" }, + { name = "flask", marker = "sys_platform == 'linux'" }, + { name = "flask-cors", marker = "sys_platform == 'linux'" }, + { name = "graphene", marker = "sys_platform == 'linux'" }, + { name = "gunicorn", marker = "sys_platform == 'linux'" }, + { name = "huey", marker = "sys_platform == 'linux'" }, + { name = "matplotlib", marker = "sys_platform == 'linux'" }, + { name = "mlflow-skinny", marker = "sys_platform == 'linux'" }, + { name = "mlflow-tracing", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "pandas", marker = "sys_platform == 'linux'" }, + { name = "pyarrow", marker = "sys_platform == 'linux'" }, + { name = "scikit-learn", marker = "sys_platform == 'linux'" }, + { name = "scipy", marker = "sys_platform == 'linux'" }, + { name = "skops", marker = "sys_platform == 'linux'" }, + { name = "sqlalchemy", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/34/e328c073cd32c186fb242a957e5bade82433c06bc45b7d1695bf4d02f166/mlflow-3.11.1.tar.gz", hash = "sha256:84e54c4be91b5b2a19039a2673fe688b1d7307ceddacc08af51f8df05b19ee56", size = 9797469, upload-time = "2026-04-07T14:26:58.463Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/62/96826c340354638dfedcbdbcd35d67754566bd45f6592300e0c215c80e30/mlflow-3.11.1-py3-none-any.whl", hash = "sha256:8f6bf1238ac04f97664c229dd480380c5c254a78bdb3c0e433e3a0397508b1af", size = 10479141, upload-time = "2026-04-07T14:26:55.709Z" }, +] + +[[package]] +name = "mlflow-skinny" +version = "3.11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools", marker = "sys_platform == 'linux'" }, + { name = "click", marker = "sys_platform == 'linux'" }, + { name = "cloudpickle", marker = "sys_platform == 'linux'" }, + { name = "databricks-sdk", marker = "sys_platform == 'linux'" }, + { name = "fastapi", marker = "sys_platform == 'linux'" }, + { name = "gitpython", marker = "sys_platform == 'linux'" }, + { name = "importlib-metadata", marker = "sys_platform == 'linux'" }, + { name = "opentelemetry-api", marker = "sys_platform == 'linux'" }, + { name = "opentelemetry-proto", marker = "sys_platform == 'linux'" }, + { name = "opentelemetry-sdk", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "protobuf", marker = "sys_platform == 'linux'" }, + { name = "pydantic", marker = "sys_platform == 'linux'" }, + { name = "python-dotenv", marker = "sys_platform == 'linux'" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, + { name = "requests", marker = "sys_platform == 'linux'" }, + { name = "sqlparse", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, + { name = "uvicorn", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/40/77/fe2027ddad9e52ed1ac360fbc262169e6366f6678632e350cbd0d901bb9b/mlflow_skinny-3.11.1.tar.gz", hash = "sha256:86ce63491349f6713afc8a4ef0bf77a8314d0e79e03753cb150d6c860a0b0475", size = 2642799, upload-time = "2026-04-07T14:26:43.818Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/a7/e61ec397b34dc3c9e91572f45e41617f429d5c524d38a4e1aa2316ee1b5e/mlflow_skinny-3.11.1-py3-none-any.whl", hash = "sha256:82ffd5f6980320b4ac19f741e7a754faa1d01707e632b002ea68e04fd25a0535", size = 3171551, upload-time = "2026-04-07T14:26:41.762Z" }, +] + +[[package]] +name = "mlflow-tracing" +version = "3.11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools", marker = "sys_platform == 'linux'" }, + { name = "databricks-sdk", marker = "sys_platform == 'linux'" }, + { name = "opentelemetry-api", marker = "sys_platform == 'linux'" }, + { name = "opentelemetry-proto", marker = "sys_platform == 'linux'" }, + { name = "opentelemetry-sdk", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "protobuf", marker = "sys_platform == 'linux'" }, + { name = "pydantic", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1b/77/73af163432f3c66e2d213045250972e504a6683c76f63dd1abfba441a16a/mlflow_tracing-3.11.1.tar.gz", hash = "sha256:cb63cee16385d081467ec5bee4807fe1af59ddfdf04be4c79e7a7813b1002193", size = 1314550, upload-time = "2026-04-07T14:26:32.785Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/ab/d980c84e7df4224ab8db2457afbe135b430f371ca081a37cf89f8ef18ca1/mlflow_tracing-3.11.1-py3-none-any.whl", hash = "sha256:fa82df64dacf8293b714ae666440fe7c1902c6470c024df389bb91e9de3106d9", size = 1575790, upload-time = "2026-04-07T14:26:30.804Z" }, +] + [[package]] name = "mmdet" version = "3.3.0" @@ -502,7 +990,7 @@ dependencies = [ { name = "matplotlib", marker = "sys_platform == 'linux'" }, { name = "mmdet", marker = "sys_platform == 'linux'" }, { name = "mmengine", marker = "sys_platform == 'linux'" }, - { name = "motrack", marker = "sys_platform == 'linux'" }, + { name = "motrack", extra = ["mlflow"], marker = "sys_platform == 'linux'" }, { name = "numpy", marker = "sys_platform == 'linux'" }, { name = "omegaconf", marker = "sys_platform == 'linux'" }, { name = "opencv-python", marker = "sys_platform == 'linux'" }, @@ -534,7 +1022,7 @@ requires-dist = [ { name = "matplotlib", specifier = ">=3.10.3" }, { name = "mmdet", specifier = ">=3.3.0" }, { name = "mmengine", specifier = ">=0.10.0" }, - { name = "motrack", specifier = ">=0.6.0" }, + { name = "motrack", extras = ["mlflow"], specifier = "==0.7.0" }, { name = "numpy", specifier = ">=1.24.0,<2.0" }, { name = "omegaconf", specifier = ">=2.3.0" }, { name = "opencv-python", specifier = ">=4.11.0.86" }, @@ -559,24 +1047,35 @@ requires-dist = [ [[package]] name = "motrack" -version = "0.6.0" +version = "0.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "hydra-core", marker = "sys_platform == 'linux'" }, { name = "matplotlib", marker = "sys_platform == 'linux'" }, + { name = "mmdet", marker = "sys_platform == 'linux'" }, + { name = "mmengine", marker = "sys_platform == 'linux'" }, { name = "motrack-motion", marker = "sys_platform == 'linux'" }, { name = "numpy", marker = "sys_platform == 'linux'" }, { name = "omegaconf", marker = "sys_platform == 'linux'" }, { name = "opencv-python", marker = "sys_platform == 'linux'" }, + { name = "openmim", marker = "sys_platform == 'linux'" }, + { name = "optuna", marker = "sys_platform == 'linux'" }, { name = "pandas", marker = "sys_platform == 'linux'" }, + { name = "pydantic", marker = "sys_platform == 'linux'" }, { name = "pyyaml", marker = "sys_platform == 'linux'" }, { name = "scipy", marker = "sys_platform == 'linux'" }, + { name = "setuptools", marker = "sys_platform == 'linux'" }, { name = "torch", marker = "sys_platform == 'linux'" }, { name = "tqdm", marker = "sys_platform == 'linux'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3f/97/1458dd53445b22b0e24906f497183bb5ffbd6b158528972a23b04b1c5c81/motrack-0.6.0.tar.gz", hash = "sha256:8812eb2e4d32525796f44f459d5cb7f5b6db0725ae075e7b44bb6d99205e079b", size = 70209, upload-time = "2026-03-29T16:38:18.19Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/c5/9daaa7c392027b09ec5e3b085554889930ab859eed3189dfac40fc6c5e9d/motrack-0.7.0.tar.gz", hash = "sha256:39b00d6ed9960b7b2b9ad58a16ab1a08a01deef5c2e17c4af1d2544f7e06c619", size = 119437, upload-time = "2026-05-01T08:41:11.398Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/a3/942b9e4a65a63c7e85354875d40f3034ff5c10037ef1b3dc2323cd132db3/motrack-0.6.0-py3-none-any.whl", hash = "sha256:8897ed8273518a25ad4b9f5033e53e3975c32fe34e7719e4717f3012f40a2ee0", size = 106782, upload-time = "2026-03-29T16:38:16.521Z" }, + { url = "https://files.pythonhosted.org/packages/46/5b/3954bf5ac6f381ef2ca530650f63c6c61d59ab3215f555bcac3b8dc05ac7/motrack-0.7.0-py3-none-any.whl", hash = "sha256:d9d3291a9b86fccff4fc2c08298f709704b2a38d95d1320958a372797e270a6b", size = 166460, upload-time = "2026-05-01T08:41:09.533Z" }, +] + +[package.optional-dependencies] +mlflow = [ + { name = "mlflow", marker = "sys_platform == 'linux'" }, ] [[package]] @@ -601,6 +1100,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, ] +[[package]] +name = "multidict" +version = "6.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/d2/0a36c8473f0cbaeadd5db6c8b72d15bbceeec275807772bfcd059bef487d/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3", size = 244355, upload-time = "2026-01-26T02:43:31.165Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/8c65be997fd7dd311b7d39c7b6e71a0cb449bad093761481eccbbe4b42a2/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e", size = 246433, upload-time = "2026-01-26T02:43:32.581Z" }, + { url = "https://files.pythonhosted.org/packages/01/fb/4dbd7e848d2799c6a026ec88ad39cf2b8416aa167fcc903baa55ecaa045c/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a", size = 225376, upload-time = "2026-01-26T02:43:34.417Z" }, + { url = "https://files.pythonhosted.org/packages/b6/8a/4a3a6341eac3830f6053062f8fbc9a9e54407c80755b3f05bc427295c2d0/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8", size = 257365, upload-time = "2026-01-26T02:43:35.741Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a2/dd575a69c1aa206e12d27d0770cdf9b92434b48a9ef0cd0d1afdecaa93c4/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0", size = 254747, upload-time = "2026-01-26T02:43:36.976Z" }, + { url = "https://files.pythonhosted.org/packages/5a/56/21b27c560c13822ed93133f08aa6372c53a8e067f11fbed37b4adcdac922/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144", size = 246293, upload-time = "2026-01-26T02:43:38.258Z" }, + { url = "https://files.pythonhosted.org/packages/5a/a4/23466059dc3854763423d0ad6c0f3683a379d97673b1b89ec33826e46728/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49", size = 242962, upload-time = "2026-01-26T02:43:40.034Z" }, + { url = "https://files.pythonhosted.org/packages/1f/67/51dd754a3524d685958001e8fa20a0f5f90a6a856e0a9dcabff69be3dbb7/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71", size = 237360, upload-time = "2026-01-26T02:43:41.752Z" }, + { url = "https://files.pythonhosted.org/packages/64/3f/036dfc8c174934d4b55d86ff4f978e558b0e585cef70cfc1ad01adc6bf18/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3", size = 245940, upload-time = "2026-01-26T02:43:43.042Z" }, + { url = "https://files.pythonhosted.org/packages/3d/20/6214d3c105928ebc353a1c644a6ef1408bc5794fcb4f170bb524a3c16311/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c", size = 253502, upload-time = "2026-01-26T02:43:44.371Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e2/c653bc4ae1be70a0f836b82172d643fcf1dade042ba2676ab08ec08bff0f/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0", size = 247065, upload-time = "2026-01-26T02:43:45.745Z" }, + { url = "https://files.pythonhosted.org/packages/c8/11/a854b4154cd3bd8b1fd375e8a8ca9d73be37610c361543d56f764109509b/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa", size = 241870, upload-time = "2026-01-26T02:43:47.054Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, +] + [[package]] name = "narwhals" version = "1.44.0" @@ -802,6 +1322,58 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/00/b3/95531cee452028869d0e08974561f83e9c256c98f62c7a45a51893a61c54/openmim-0.3.9-py2.py3-none-any.whl", hash = "sha256:71581498b68767f8e1f340575b91c9994ccc93656901639f11300e46247da263", size = 52660, upload-time = "2023-06-28T07:45:42.832Z" }, ] +[[package]] +name = "opentelemetry-api" +version = "1.41.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fa/fc/b7564cbef36601aef0d6c9bc01f7badb64be8e862c2e1c3c5c3b43b53e4f/opentelemetry_api-1.41.1.tar.gz", hash = "sha256:0ad1814d73b875f84494387dae86ce0b12c68556331ce6ce8fe789197c949621", size = 71416, upload-time = "2026-04-24T13:15:38.262Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/59/3e7118ed140f76b0982ba4321bdaed1997a0473f9720de2d10788a577033/opentelemetry_api-1.41.1-py3-none-any.whl", hash = "sha256:a22df900e75c76dc08440710e51f52f1aa6b451b429298896023e60db5b3139f", size = 69007, upload-time = "2026-04-24T13:15:15.662Z" }, +] + +[[package]] +name = "opentelemetry-proto" +version = "1.41.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/e8/633c6d8a9c8840338b105907e55c32d3da1983abab5e52f899f72a82c3d1/opentelemetry_proto-1.41.1.tar.gz", hash = "sha256:4b9d2eb631237ea43b80e16c073af438554e32bc7e9e3f8ca4a9582f900020e5", size = 45670, upload-time = "2026-04-24T13:15:49.768Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/1e/5cd77035e3e82070e2265a63a760f715aacd3cb16dddc7efee913f297fcc/opentelemetry_proto-1.41.1-py3-none-any.whl", hash = "sha256:0496713b804d127a4147e32849fbaf5683fac8ee98550e8e7679cd706c289720", size = 72076, upload-time = "2026-04-24T13:15:32.542Z" }, +] + +[[package]] +name = "opentelemetry-sdk" +version = "1.41.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api", marker = "sys_platform == 'linux'" }, + { name = "opentelemetry-semantic-conventions", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/d0/54ee30dab82fb0acda23d144502771ff76ef8728459c83c3e89ef9fb1825/opentelemetry_sdk-1.41.1.tar.gz", hash = "sha256:724b615e1215b5aeacda0abb8a6a8922c9a1853068948bd0bd225a56d0c792e6", size = 230180, upload-time = "2026-04-24T13:15:50.991Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/e7/a1420b698aad018e1cf60fdbaaccbe49021fb415e2a0d81c242f4c518f54/opentelemetry_sdk-1.41.1-py3-none-any.whl", hash = "sha256:edee379c126c1bce952b0c812b48fe8ff35b30df0eecf17e98afa4d598b7d85d", size = 180213, upload-time = "2026-04-24T13:15:33.767Z" }, +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.62b1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/de/911ac9e309052aca1b20b2d5549d3db45d1011e1a610e552c6ccdd1b64f8/opentelemetry_semantic_conventions-0.62b1.tar.gz", hash = "sha256:c5cc6e04a7f8c7cdd30be2ed81499fa4e75bfbd52c9cb70d40af1f9cd3619802", size = 145750, upload-time = "2026-04-24T13:15:52.236Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/a6/83dc2ab6fa397ee66fba04fe2e74bdf7be3b3870005359ceb7689103c058/opentelemetry_semantic_conventions-0.62b1-py3-none-any.whl", hash = "sha256:cf506938103d331fbb78eded0d9788095f7fd59016f2bda813c3324e5a74a93c", size = 231620, upload-time = "2026-04-24T13:15:35.454Z" }, +] + [[package]] name = "openxlab" version = "0.0.11" @@ -811,6 +1383,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/20/cd2ffb50efceac4fe4d9193e2ce5f7e00813cc10203c1a714d3247452d9c/openxlab-0.0.11-py3-none-any.whl", hash = "sha256:ab594a0f8c6f74501ab6c82a823c17bd2d038f72ee47a41fbac2c801df68565a", size = 55314, upload-time = "2023-06-19T02:47:21.032Z" }, ] +[[package]] +name = "optuna" +version = "4.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "alembic", marker = "sys_platform == 'linux'" }, + { name = "colorlog", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, + { name = "sqlalchemy", marker = "sys_platform == 'linux'" }, + { name = "tqdm", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/9b/62f120fb2ecbc4338bee70c5a3671c8e561714f3aa1a046b897ff142050e/optuna-4.8.0.tar.gz", hash = "sha256:6f7043e9f8ecb5e607af86a7eb00fb5ec2be26c3b08c201209a73d36aff37a38", size = 482603, upload-time = "2026-03-16T04:59:58.659Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/24/7c731839566d30dc70556d9824ef17692d896c15e3df627bce8c16f753e1/optuna-4.8.0-py3-none-any.whl", hash = "sha256:c57a7682679c36bfc9bca0da430698179e513874074b71bebedb0334964ab930", size = 419456, upload-time = "2026-03-16T04:59:56.977Z" }, +] + [[package]] name = "ordered-set" version = "4.1.0" @@ -905,6 +1495,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] +[[package]] +name = "prettytable" +version = "3.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/45/b0847d88d6cfeb4413566738c8bbf1e1995fad3d42515327ff32cc1eb578/prettytable-3.17.0.tar.gz", hash = "sha256:59f2590776527f3c9e8cf9fe7b66dd215837cca96a9c39567414cbc632e8ddb0", size = 67892, upload-time = "2025-11-14T17:33:20.212Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/8c/83087ebc47ab0396ce092363001fa37c17153119ee282700c0713a195853/prettytable-3.17.0-py3-none-any.whl", hash = "sha256:aad69b294ddbe3e1f95ef8886a060ed1666a0b83018bbf56295f6f226c43d287", size = 34433, upload-time = "2025-11-14T17:33:19.093Z" }, +] + +[[package]] +name = "propcache" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/1a/3c62c127a8466c9c843bccb503d40a273e5cc69838805f322e2826509e0d/propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566", size = 214929, upload-time = "2025-10-08T19:46:28.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/b9/8fa98f850960b367c4b8fe0592e7fc341daa7a9462e925228f10a60cf74f/propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165", size = 221778, upload-time = "2025-10-08T19:46:30.358Z" }, + { url = "https://files.pythonhosted.org/packages/46/a6/0ab4f660eb59649d14b3d3d65c439421cf2f87fe5dd68591cbe3c1e78a89/propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc", size = 228144, upload-time = "2025-10-08T19:46:32.607Z" }, + { url = "https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48", size = 210030, upload-time = "2025-10-08T19:46:33.969Z" }, + { url = "https://files.pythonhosted.org/packages/40/e2/27e6feebb5f6b8408fa29f5efbb765cd54c153ac77314d27e457a3e993b7/propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570", size = 208252, upload-time = "2025-10-08T19:46:35.309Z" }, + { url = "https://files.pythonhosted.org/packages/9e/f8/91c27b22ccda1dbc7967f921c42825564fa5336a01ecd72eb78a9f4f53c2/propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85", size = 202064, upload-time = "2025-10-08T19:46:36.993Z" }, + { url = "https://files.pythonhosted.org/packages/f2/26/7f00bd6bd1adba5aafe5f4a66390f243acab58eab24ff1a08bebb2ef9d40/propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e", size = 212429, upload-time = "2025-10-08T19:46:38.398Z" }, + { url = "https://files.pythonhosted.org/packages/84/89/fd108ba7815c1117ddca79c228f3f8a15fc82a73bca8b142eb5de13b2785/propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757", size = 216727, upload-time = "2025-10-08T19:46:39.732Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/3ec3f7e3173e73f1d600495d8b545b53802cbf35506e5732dd8578db3724/propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f", size = 205097, upload-time = "2025-10-08T19:46:41.025Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, +] + [[package]] name = "protobuf" version = "6.31.1" @@ -916,6 +1536,39 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f7/af/ab3c51ab7507a7325e98ffe691d9495ee3d3aa5f589afad65ec920d39821/protobuf-6.31.1-py3-none-any.whl", hash = "sha256:720a6c7e6b77288b85063569baae8536671b39f15cc22037ec7045658d80489e", size = 168724, upload-time = "2025-05-28T19:25:53.926Z" }, ] +[[package]] +name = "pyarrow" +version = "23.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/88/22/134986a4cc224d593c1afde5494d18ff629393d74cc2eddb176669f234a4/pyarrow-23.0.1.tar.gz", hash = "sha256:b8c5873e33440b2bc2f4a79d2b47017a89c5a24116c055625e6f2ee50523f019", size = 1167336, upload-time = "2026-02-16T10:14:12.39Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/b2/bd1f2f05ded56af7f54d702c8364c9c43cd6abb91b0e9933f3d77b4f4132/pyarrow-23.0.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:fed7020203e9ef273360b9e45be52a2a47d3103caf156a30ace5247ffb51bdbd", size = 44491918, upload-time = "2026-02-16T10:09:18.144Z" }, + { url = "https://files.pythonhosted.org/packages/0b/62/96459ef5b67957eac38a90f541d1c28833d1b367f014a482cb63f3b7cd2d/pyarrow-23.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:26d50dee49d741ac0e82185033488d28d35be4d763ae6f321f97d1140eb7a0e9", size = 47562811, upload-time = "2026-02-16T10:09:25.792Z" }, + { url = "https://files.pythonhosted.org/packages/7d/94/1170e235add1f5f45a954e26cd0e906e7e74e23392dcb560de471f7366ec/pyarrow-23.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c30143b17161310f151f4a2bcfe41b5ff744238c1039338779424e38579d701", size = 48183766, upload-time = "2026-02-16T10:09:34.645Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/39a42af4570377b99774cdb47f63ee6c7da7616bd55b3d5001aa18edfe4f/pyarrow-23.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db2190fa79c80a23fdd29fef4b8992893f024ae7c17d2f5f4db7171fa30c2c78", size = 50607669, upload-time = "2026-02-16T10:09:44.153Z" }, +] + +[[package]] +name = "pyasn1" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, +] + [[package]] name = "pycocotools" version = "2.0.11" @@ -935,6 +1588,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/63/b5/519bb68647f06feea03d5f355c33c05800aeae4e57b9482b2859eb00752e/pycocotools-2.0.11-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:87af87b8d06d5b852a885a319d9362dca3bed9f8bbcc3feb6513acb1f88ea242", size = 409790, upload-time = "2025-12-15T22:31:16.326Z" }, ] +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + [[package]] name = "pycryptodome" version = "3.23.0" @@ -951,7 +1613,7 @@ wheels = [ [[package]] name = "pydantic" -version = "2.11.7" +version = "2.13.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types", marker = "sys_platform == 'linux'" }, @@ -959,35 +1621,37 @@ dependencies = [ { name = "typing-extensions", marker = "sys_platform == 'linux'" }, { name = "typing-inspection", marker = "sys_platform == 'linux'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d9/e4/40d09941a2cebcb20609b86a559817d5b9291c49dd6f8c87e5feffbe703a/pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d", size = 844068, upload-time = "2026-04-20T14:46:43.632Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, + { url = "https://files.pythonhosted.org/packages/f3/0a/fd7d723f8f8153418fb40cf9c940e82004fce7e987026b08a68a36dd3fe7/pydantic-2.13.3-py3-none-any.whl", hash = "sha256:6db14ac8dfc9a1e57f87ea2c0de670c251240f43cb0c30a5130e9720dc612927", size = 471981, upload-time = "2026-04-20T14:46:41.402Z" }, ] [[package]] name = "pydantic-core" -version = "2.33.2" +version = "2.46.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "sys_platform == 'linux'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/ef/f7abb56c49382a246fd2ce9c799691e3c3e7175ec74b14d99e798bcddb1a/pydantic_core-2.46.3.tar.gz", hash = "sha256:41c178f65b8c29807239d47e6050262eb6bf84eb695e41101e62e38df4a5bc2c", size = 471412, upload-time = "2026-04-20T14:40:56.672Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" }, - { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" }, - { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" }, - { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" }, - { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" }, - { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" }, - { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" }, - { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" }, - { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" }, - { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" }, - { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" }, - { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" }, - { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" }, + { url = "https://files.pythonhosted.org/packages/3e/b8/2e8e636dc9e3f16c2e16bf0849e24be82c5ee82c603c65fc0326666328fc/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c024e08c0ba23e6fd68c771a521e9d6a792f2ebb0fa734296b36394dc30390e", size = 1973222, upload-time = "2026-04-20T14:41:57.841Z" }, + { url = "https://files.pythonhosted.org/packages/34/36/0e730beec4d83c5306f417afbd82ff237d9a21e83c5edf675f31ed84c1fe/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6645ce7eec4928e29a1e3b3d5c946621d105d3e79f0c9cddf07c2a9770949287", size = 2053852, upload-time = "2026-04-20T14:40:43.077Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f0/3071131f47e39136a17814576e0fada9168569f7f8c0e6ac4d1ede6a4958/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a712c7118e6c5ea96562f7b488435172abb94a3c53c22c9efc1412264a45cbbe", size = 2221134, upload-time = "2026-04-20T14:43:03.349Z" }, + { url = "https://files.pythonhosted.org/packages/2f/a9/a2dc023eec5aa4b02a467874bad32e2446957d2adcab14e107eab502e978/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a868ef3ff206343579021c40faf3b1edc64b1cc508ff243a28b0a514ccb050", size = 2279785, upload-time = "2026-04-20T14:41:19.285Z" }, + { url = "https://files.pythonhosted.org/packages/0a/44/93f489d16fb63fbd41c670441536541f6e8cfa1e5a69f40bc9c5d30d8c90/pydantic_core-2.46.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc7e8c32db809aa0f6ea1d6869ebc8518a65d5150fdfad8bcae6a49ae32a22e2", size = 2089404, upload-time = "2026-04-20T14:43:10.108Z" }, + { url = "https://files.pythonhosted.org/packages/2a/78/8692e3aa72b2d004f7a5d937f1dfdc8552ba26caf0bec75f342c40f00dec/pydantic_core-2.46.3-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:3481bd1341dc85779ee506bc8e1196a277ace359d89d28588a9468c3ecbe63fa", size = 2114898, upload-time = "2026-04-20T14:44:51.475Z" }, + { url = "https://files.pythonhosted.org/packages/6a/62/e83133f2e7832532060175cebf1f13748f4c7e7e7165cdd1f611f174494b/pydantic_core-2.46.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8690eba565c6d68ffd3a8655525cbdd5246510b44a637ee2c6c03a7ebfe64d3c", size = 2157856, upload-time = "2026-04-20T14:43:46.64Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ec/6a500e3ad7718ee50583fae79c8651f5d37e3abce1fa9ae177ae65842c53/pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4de88889d7e88d50d40ee5b39d5dac0bcaef9ba91f7e536ac064e6b2834ecccf", size = 2180168, upload-time = "2026-04-20T14:42:00.302Z" }, + { url = "https://files.pythonhosted.org/packages/d8/53/8267811054b1aa7fc1dc7ded93812372ef79a839f5e23558136a6afbfde1/pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:e480080975c1ef7f780b8f99ed72337e7cc5efea2e518a20a692e8e7b278eb8b", size = 2322885, upload-time = "2026-04-20T14:41:05.253Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c1/1c0acdb3aa0856ddc4ecc55214578f896f2de16f400cf51627eb3c26c1c4/pydantic_core-2.46.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:de3a5c376f8cd94da9a1b8fd3dd1c16c7a7b216ed31dc8ce9fd7a22bf13b836e", size = 2360328, upload-time = "2026-04-20T14:41:43.991Z" }, + { url = "https://files.pythonhosted.org/packages/0d/ca/d376391a5aff1f2e8188960d7873543608130a870961c2b6b5236627c116/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd2aab0e2e9dc2daf36bd2686c982535d5e7b1d930a1344a7bb6e82baab42a76", size = 1988172, upload-time = "2026-04-20T14:41:17.469Z" }, + { url = "https://files.pythonhosted.org/packages/0e/6b/523b9f85c23788755d6ab949329de692a2e3a584bc6beb67fef5e035aa9d/pydantic_core-2.46.3-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e9d76736da5f362fabfeea6a69b13b7f2be405c6d6966f06b2f6bfff7e64531", size = 2128596, upload-time = "2026-04-20T14:40:41.707Z" }, + { url = "https://files.pythonhosted.org/packages/60/62/0c1acfe10945b83a6a59d19fbaa92f48825381509e5701b855c08f13db76/pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6529d1d128321a58d30afcc97b49e98836542f68dd41b33c2e972bb9e5290536", size = 2123791, upload-time = "2026-04-20T14:43:22.766Z" }, + { url = "https://files.pythonhosted.org/packages/75/3e/3b2393b4c8f44285561dc30b00cf307a56a2eff7c483a824db3b8221ca51/pydantic_core-2.46.3-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:975c267cff4f7e7272eacbe50f6cc03ca9a3da4c4fbd66fffd89c94c1e311aa1", size = 2153197, upload-time = "2026-04-20T14:44:27.932Z" }, + { url = "https://files.pythonhosted.org/packages/ba/75/5af02fb35505051eee727c061f2881c555ab4f8ddb2d42da715a42c9731b/pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2b8e4f2bbdf71415c544b4b1138b8060db7b6611bc927e8064c769f64bed651c", size = 2181073, upload-time = "2026-04-20T14:43:20.729Z" }, + { url = "https://files.pythonhosted.org/packages/10/92/7e0e1bd9ca3c68305db037560ca2876f89b2647deb2f8b6319005de37505/pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e61ea8e9fff9606d09178f577ff8ccdd7206ff73d6552bcec18e1033c4254b85", size = 2315886, upload-time = "2026-04-20T14:44:04.826Z" }, + { url = "https://files.pythonhosted.org/packages/b8/d8/101655f27eaf3e44558ead736b2795d12500598beed4683f279396fa186e/pydantic_core-2.46.3-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b504bda01bafc69b6d3c7a0c7f039dcf60f47fab70e06fe23f57b5c75bdc82b8", size = 2360528, upload-time = "2026-04-20T14:40:47.431Z" }, ] [[package]] @@ -1052,6 +1716,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] +[[package]] +name = "python-dotenv" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, +] + [[package]] name = "pytorch-metric-learning" version = "2.8.1" @@ -1208,6 +1881,70 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] +[[package]] +name = "skops" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "prettytable", marker = "sys_platform == 'linux'" }, + { name = "scikit-learn", marker = "sys_platform == 'linux'" }, + { name = "scipy", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c8/9f/46448c4e41a4c5ee4bdb74b3758af48e5ff0faeffe40f4e301bfc7594894/skops-0.14.0.tar.gz", hash = "sha256:6c8c0e047f691a3a582c3258943eecafcbfd79c8c7eef66260f3703e363254f0", size = 608084, upload-time = "2026-04-20T18:23:55.336Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/0e/3ae19fa941522cd98e119762e7181d371c8dba0b2d72bfaf9522692e329c/skops-0.14.0-py3-none-any.whl", hash = "sha256:60a5db78a9db46ccee2139a0ba13ab5afb1c96f4749b382e75a371291bbe3e36", size = 132198, upload-time = "2026-04-20T18:23:54.018Z" }, +] + +[[package]] +name = "smmap" +version = "5.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/ea/49c993d6dfdd7338c9b1000a0f36817ed7ec84577ae2e52f890d1a4ff909/smmap-5.0.3.tar.gz", hash = "sha256:4d9debb8b99007ae47165abc08670bd74cb74b5227dda7f643eccc4e9eb5642c", size = 22506, upload-time = "2026-03-09T03:43:26.1Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl", hash = "sha256:c106e05d5a61449cf6ba9a1e650227ecfb141590d2a98412103ff35d89fc7b2f", size = 24390, upload-time = "2026-03-09T03:43:24.361Z" }, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.49" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet", marker = "(platform_machine == 'AMD64' and sys_platform == 'linux') or (platform_machine == 'WIN32' and sys_platform == 'linux') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'amd64' and sys_platform == 'linux') or (platform_machine == 'ppc64le' and sys_platform == 'linux') or (platform_machine == 'win32' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/45/461788f35e0364a8da7bda51a1fe1b09762d0c32f12f63727998d85a873b/sqlalchemy-2.0.49.tar.gz", hash = "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f", size = 9898221, upload-time = "2026-04-03T16:38:11.704Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/9b/91ca80403b17cd389622a642699e5f6564096b698e7cdcbcbb6409898bc4/sqlalchemy-2.0.49-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9ac7a3e245fd0310fd31495eb61af772e637bdf7d88ee81e7f10a3f271bff014", size = 3315509, upload-time = "2026-04-03T16:54:49.332Z" }, + { url = "https://files.pythonhosted.org/packages/b1/61/0722511d98c54de95acb327824cb759e8653789af2b1944ab1cc69d32565/sqlalchemy-2.0.49-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d4e5a0ceba319942fa6b585cf82539288a61e314ef006c1209f734551ab9536", size = 3315014, upload-time = "2026-04-03T16:56:56.376Z" }, + { url = "https://files.pythonhosted.org/packages/46/55/d514a653ffeb4cebf4b54c47bec32ee28ad89d39fafba16eeed1d81dccd5/sqlalchemy-2.0.49-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ddcb27fb39171de36e207600116ac9dfd4ae46f86c82a9bf3934043e80ebb88", size = 3267388, upload-time = "2026-04-03T16:54:51.272Z" }, + { url = "https://files.pythonhosted.org/packages/2f/16/0dcc56cb6d3335c1671a2258f5d2cb8267c9a2260e27fde53cbfb1b3540a/sqlalchemy-2.0.49-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:32fe6a41ad97302db2931f05bb91abbcc65b5ce4c675cd44b972428dd2947700", size = 3289602, upload-time = "2026-04-03T16:56:57.63Z" }, + { url = "https://files.pythonhosted.org/packages/e5/30/8519fdde58a7bdf155b714359791ad1dc018b47d60269d5d160d311fdc36/sqlalchemy-2.0.49-py3-none-any.whl", hash = "sha256:ec44cfa7ef1a728e88ad41674de50f6db8cfdb3e2af84af86e0041aaf02d43d0", size = 1942158, upload-time = "2026-04-03T16:53:44.135Z" }, +] + +[[package]] +name = "sqlparse" +version = "0.5.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, +] + +[[package]] +name = "starlette" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/81/69/17425771797c36cded50b7fe44e850315d039f28b15901ab44839e70b593/starlette-1.0.0.tar.gz", hash = "sha256:6a4beaf1f81bb472fd19ea9b918b50dc3a77a6f2e190a12954b25e6ed5eea149", size = 2655289, upload-time = "2026-03-22T18:29:46.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/c9/584bc9651441b4ba60cc4d557d8a547b5aff901af35bda3a4ee30c819b82/starlette-1.0.0-py3-none-any.whl", hash = "sha256:d3ec55e0bb321692d275455ddfd3df75fff145d009685eb40dc91fc66b03d38b", size = 72651, upload-time = "2026-03-22T18:29:45.111Z" }, +] + [[package]] name = "sympy" version = "1.13.1" @@ -1399,23 +2136,23 @@ wheels = [ [[package]] name = "typing-extensions" -version = "4.14.0" +version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] [[package]] name = "typing-inspection" -version = "0.4.1" +version = "0.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "sys_platform == 'linux'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, ] [[package]] @@ -1436,6 +2173,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, ] +[[package]] +name = "uvicorn" +version = "0.46.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click", marker = "sys_platform == 'linux'" }, + { name = "h11", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/93/041fca8274050e40e6791f267d82e0e2e27dd165627bd640d3e0e378d877/uvicorn-0.46.0.tar.gz", hash = "sha256:fb9da0926999cc6cb22dc7cd71a94a632f078e6ae47ff683c5c420750fb7413d", size = 88758, upload-time = "2026-04-23T07:16:00.151Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/a3/5b1562db76a5a488274b2332a97199b32d0442aca0ed193697fd47786316/uvicorn-0.46.0-py3-none-any.whl", hash = "sha256:bbebbcbed972d162afca128605223022bedd345b7bc7855ce66deb31487a9048", size = 70926, upload-time = "2026-04-23T07:15:58.355Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/a2/8e3becb46433538a38726c948d3399905a4c7cabd0df578ede5dc51f0ec2/wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159", size = 159684, upload-time = "2026-02-06T19:19:40.919Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189, upload-time = "2026-02-06T19:19:39.646Z" }, +] + [[package]] name = "werkzeug" version = "3.1.3" @@ -1459,3 +2218,38 @@ sdist = { url = "https://files.pythonhosted.org/packages/23/97/b6f296d1e9cc1ec25 wheels = [ { url = "https://files.pythonhosted.org/packages/37/81/6acd6601f61e31cfb8729d3da6d5df966f80f374b78eff83760714487338/yapf-0.43.0-py3-none-any.whl", hash = "sha256:224faffbc39c428cb095818cf6ef5511fdab6f7430a10783fdfb292ccf2852ca", size = 256158, upload-time = "2024-11-14T00:11:39.37Z" }, ] + +[[package]] +name = "yarl" +version = "1.23.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna", marker = "sys_platform == 'linux'" }, + { name = "multidict", marker = "sys_platform == 'linux'" }, + { name = "propcache", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/6c/4a90d59c572e46b270ca132aca66954f1175abd691f74c1ef4c6711828e2/yarl-1.23.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2c6b50c7b0464165472b56b42d4c76a7b864597007d9c085e8b63e185cf4a7a", size = 100566, upload-time = "2026-03-01T22:04:47.639Z" }, + { url = "https://files.pythonhosted.org/packages/49/fb/c438fb5108047e629f6282a371e6e91cf3f97ee087c4fb748a1f32ceef55/yarl-1.23.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aafe5dcfda86c8af00386d7781d4c2181b5011b7be3f2add5e99899ea925df05", size = 92079, upload-time = "2026-03-01T22:04:48.925Z" }, + { url = "https://files.pythonhosted.org/packages/d9/13/d269aa1aed3e4f50a5a103f96327210cc5fa5dd2d50882778f13c7a14606/yarl-1.23.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ee33b875f0b390564c1fb7bc528abf18c8ee6073b201c6ae8524aca778e2d83", size = 108741, upload-time = "2026-03-01T22:04:50.838Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/115b16f22c37ea4437d323e472945bea97301c8ec6089868fa560abab590/yarl-1.23.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c41e021bc6d7affb3364dc1e1e5fa9582b470f283748784bd6ea0558f87f42c", size = 108099, upload-time = "2026-03-01T22:04:52.499Z" }, + { url = "https://files.pythonhosted.org/packages/9a/64/c53487d9f4968045b8afa51aed7ca44f58b2589e772f32745f3744476c82/yarl-1.23.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99c8a9ed30f4164bc4c14b37a90208836cbf50d4ce2a57c71d0f52c7fb4f7598", size = 102678, upload-time = "2026-03-01T22:04:55.176Z" }, + { url = "https://files.pythonhosted.org/packages/85/59/cd98e556fbb2bf8fab29c1a722f67ad45c5f3447cac798ab85620d1e70af/yarl-1.23.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f2af5c81a1f124609d5f33507082fc3f739959d4719b56877ab1ee7e7b3d602b", size = 100803, upload-time = "2026-03-01T22:04:56.588Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c0/b39770b56d4a9f0bb5f77e2f1763cd2d75cc2f6c0131e3b4c360348fcd65/yarl-1.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6b41389c19b07c760c7e427a3462e8ab83c4bb087d127f0e854c706ce1b9215c", size = 100163, upload-time = "2026-03-01T22:04:58.492Z" }, + { url = "https://files.pythonhosted.org/packages/e7/64/6980f99ab00e1f0ff67cb84766c93d595b067eed07439cfccfc8fb28c1a6/yarl-1.23.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1dc702e42d0684f42d6519c8d581e49c96cefaaab16691f03566d30658ee8788", size = 93859, upload-time = "2026-03-01T22:05:00.268Z" }, + { url = "https://files.pythonhosted.org/packages/38/69/912e6c5e146793e5d4b5fe39ff5b00f4d22463dfd5a162bec565ac757673/yarl-1.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0e40111274f340d32ebcc0a5668d54d2b552a6cca84c9475859d364b380e3222", size = 108202, upload-time = "2026-03-01T22:05:02.273Z" }, + { url = "https://files.pythonhosted.org/packages/59/97/35ca6767524687ad64e5f5c31ad54bc76d585585a9fcb40f649e7e82ffed/yarl-1.23.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:4764a6a7588561a9aef92f65bda2c4fb58fe7c675c0883862e6df97559de0bfb", size = 99866, upload-time = "2026-03-01T22:05:03.597Z" }, + { url = "https://files.pythonhosted.org/packages/d3/1c/1a3387ee6d73589f6f2a220ae06f2984f6c20b40c734989b0a44f5987308/yarl-1.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:03214408cfa590df47728b84c679ae4ef00be2428e11630277be0727eba2d7cc", size = 107852, upload-time = "2026-03-01T22:05:04.986Z" }, + { url = "https://files.pythonhosted.org/packages/a4/b8/35c0750fcd5a3f781058bfd954515dd4b1eab45e218cbb85cf11132215f1/yarl-1.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:170e26584b060879e29fac213e4228ef063f39128723807a312e5c7fec28eff2", size = 102919, upload-time = "2026-03-01T22:05:06.397Z" }, + { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" }, +] + +[[package]] +name = "zipp" +version = "3.23.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/21/093488dfc7cc8964ded15ab726fad40f25fd3d788fd741cc1c5a17d78ee8/zipp-3.23.1.tar.gz", hash = "sha256:32120e378d32cd9714ad503c1d024619063ec28aad2248dc6672ad13edfa5110", size = 25965, upload-time = "2026-04-13T23:21:46.6Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/8a/0861bec20485572fbddf3dfba2910e38fe249796cb73ecdeb74e07eeb8d3/zipp-3.23.1-py3-none-any.whl", hash = "sha256:0b3596c50a5c700c9cb40ba8d86d9f2cc4807e9bedb06bcdf7fac85633e444dc", size = 10378, upload-time = "2026-04-13T23:21:45.386Z" }, +]