diff --git a/boxmot/configs/search/__init__.py b/boxmot/configs/search/__init__.py new file mode 100644 index 000000000..4f7a4d0f1 --- /dev/null +++ b/boxmot/configs/search/__init__.py @@ -0,0 +1 @@ +# Mikel Broström 🔥 Yolo Tracking 🧾 AGPL-3.0 license diff --git a/boxmot/configs/search/botsort.yaml b/boxmot/configs/search/botsort.yaml new file mode 100644 index 000000000..71ea1c776 --- /dev/null +++ b/boxmot/configs/search/botsort.yaml @@ -0,0 +1,37 @@ +# botsort_search_space.yaml + +track_high_thresh: + type: uniform + range: [0.3, 0.7] + +track_low_thresh: + type: uniform + range: [0.1, 0.3] + +new_track_thresh: + type: uniform + range: [0.1, 0.8] + +track_buffer: + type: randint + range: [20, 81] + +match_thresh: + type: uniform + range: [0.1, 0.9] + +proximity_thresh: + type: uniform + range: [0.25, 0.75] + +appearance_thresh: + type: uniform + range: [0.1, 0.8] + +cmc_method: + type: choice + options: ['sparseOptFlow'] + +frame_rate: + type: choice + options: [30] diff --git a/boxmot/configs/search/bytetrack.yaml b/boxmot/configs/search/bytetrack.yaml new file mode 100644 index 000000000..c1249cc46 --- /dev/null +++ b/boxmot/configs/search/bytetrack.yaml @@ -0,0 +1,13 @@ +# bytetrack_search_space.yaml + +track_thresh: + type: uniform + range: [0.4, 0.6] + +track_buffer: + type: randint + range: [10, 61, 10] # The upper bound is exclusive, step size of 10 + +match_thresh: + type: uniform + range: [0.7, 0.9] \ No newline at end of file diff --git a/boxmot/configs/search/deepocsort.yaml b/boxmot/configs/search/deepocsort.yaml new file mode 100644 index 000000000..1badbe257 --- /dev/null +++ b/boxmot/configs/search/deepocsort.yaml @@ -0,0 +1,61 @@ +# deepocsort_search_space.yaml + +det_thresh: + type: uniform + range: [0.3, 0.6] + +max_age: + type: randint + range: [10, 61, 10] # The upper bound is exclusive, step size of 10 + +min_hits: + type: randint + range: [1, 6] # The upper bound is exclusive + +iou_thresh: + type: uniform + range: [0.1, 0.4] + +delta_t: + type: randint + range: [1, 6] # The upper bound is exclusive + +asso_func: + type: choice + options: ['iou', 'giou'] + +inertia: + type: uniform + range: [0.1, 0.4] + +w_association_emb: + type: uniform + range: [0.5, 0.9] + +alpha_fixed_emb: + type: uniform + range: [0.9, 0.999] + +aw_param: + type: uniform + range: [0.3, 0.7] + +embedding_off: + type: choice + options: [True, False] + +cmc_off: + type: choice + options: [True, False] + +aw_off: + type: choice + options: [True, False] + +Q_xy_scaling: + type: uniform + range: [0.01, 1] + +Q_s_scaling: + type: uniform + range: [0.0001, 1] diff --git a/boxmot/configs/search/hybridsort.yaml b/boxmot/configs/search/hybridsort.yaml new file mode 100644 index 000000000..677968e5b --- /dev/null +++ b/boxmot/configs/search/hybridsort.yaml @@ -0,0 +1,41 @@ +# hybridsort_search_space.yaml + +det_thresh: + type: uniform + range: [0, 0.6] + +max_age: + type: randint + range: [10, 151, 10] # The upper bound is exclusive, step size of 10 + +min_hits: + type: randint + range: [1, 6] # The upper bound is exclusive + +delta_t: + type: randint + range: [1, 6] # The upper bound is exclusive + +asso_func: + type: choice + options: ['iou', 'giou', 'diou'] + +iou_thresh: + type: uniform + range: [0.1, 0.4] + +inertia: + type: uniform + range: [0.1, 0.4] + +TCM_first_step_weight: + type: uniform + range: [0, 0.5] + +longterm_reid_weight: + type: uniform + range: [0, 0.5] + +use_byte: + type: choice + options: [True, False] \ No newline at end of file diff --git a/boxmot/configs/search/imprassoc.yaml b/boxmot/configs/search/imprassoc.yaml new file mode 100644 index 000000000..9fb5e7c17 --- /dev/null +++ b/boxmot/configs/search/imprassoc.yaml @@ -0,0 +1,49 @@ +# imprassoc_search_space.yaml + +track_high_thresh: + type: uniform + range: [0.3, 0.7] + +track_low_thresh: + type: uniform + range: [0.1, 0.3] + +new_track_thresh: + type: uniform + range: [0.1, 0.8] + +track_buffer: + type: qrandint + range: [20, 80, 10] # The upper bound is exclusive, step size of 10 + +match_thresh: + type: uniform + range: [0.1, 0.9] + +second_match_thresh: + type: uniform + range: [0.1, 0.4] + +overlap_thresh: + type: uniform + range: [0.3, 0.6] + +proximity_thresh: + type: uniform + range: [0.1, 0.8] + +appearance_thresh: + type: uniform + range: [0.1, 0.8] + +cmc_method: + type: choice + options: ['sparseOptFlow'] + +frame_rate: + type: choice + options: [30] + +lambda_: + type: uniform + range: [0.97, 0.995] diff --git a/boxmot/configs/search/ocsort.yaml b/boxmot/configs/search/ocsort.yaml new file mode 100644 index 000000000..70f243765 --- /dev/null +++ b/boxmot/configs/search/ocsort.yaml @@ -0,0 +1,37 @@ +# ocsort_search_space.yaml + +det_thresh: + type: uniform + range: [0, 0.6] + +max_age: + type: grid_search + values: [10, 20, 30, 40, 50, 60] # Discrete values using grid search + +min_hits: + type: grid_search + values: [1, 2, 3, 4, 5] # Discrete values using grid search + +delta_t: + type: grid_search + values: [1, 2, 3, 4, 5] # Discrete values using grid search + +asso_func: + type: choice + options: ['iou', 'giou', 'centroid'] + +use_byte: + type: choice + options: [True, False] + +inertia: + type: uniform + range: [0.1, 0.4] + +Q_xy_scaling: + type: loguniform + range: [0.01, 1] + +Q_s_scaling: + type: loguniform + range: [0.0001, 1] \ No newline at end of file diff --git a/boxmot/configs/search/strongsort.yaml b/boxmot/configs/search/strongsort.yaml new file mode 100644 index 000000000..357fcb445 --- /dev/null +++ b/boxmot/configs/search/strongsort.yaml @@ -0,0 +1,29 @@ +# strongsort_search_space.yaml + +ema_alpha: + type: uniform + range: [0.7, 0.95] + +max_cos_dist: + type: uniform + range: [0.1, 0.4] + +max_iou_dist: + type: uniform + range: [0.5, 0.95] + +max_age: + type: randint + range: [10, 151] # The upper bound is exclusive + +n_init: + type: randint + range: [1, 4] # The upper bound is exclusive + +mc_lambda: + type: uniform + range: [0.90, 0.999] + +nn_budget: + type: choice + options: [100] \ No newline at end of file diff --git a/boxmot/utils/__init__.py b/boxmot/utils/__init__.py index 238a1e9d3..004f91476 100644 --- a/boxmot/utils/__init__.py +++ b/boxmot/utils/__init__.py @@ -12,6 +12,7 @@ BOXMOT = ROOT / "boxmot" EXAMPLES = ROOT / "tracking" TRACKER_CONFIGS = ROOT / "boxmot" / "configs" / "defaults" +TRACKER_SEARCH_SPACES = ROOT / "boxmot" / "configs" / "search" WEIGHTS = ROOT / "tracking" / "weights" REQUIREMENTS = ROOT / "requirements.txt" diff --git a/tracking/evolve.py b/tracking/evolve.py index d3f550c86..366188906 100644 --- a/tracking/evolve.py +++ b/tracking/evolve.py @@ -4,7 +4,7 @@ from pathlib import Path from boxmot.utils.checks import RequirementsChecker -from boxmot.utils import EXAMPLES +from boxmot.utils import EXAMPLES, TRACKER_SEARCH_SPACES from tracking.val import ( run_generate_dets_embs, run_generate_mot_results, @@ -38,103 +38,46 @@ def objective_function(self, config): combined_results = {key: results.get(key) for key in self.opt.objectives} return combined_results + +def load_yaml_config(tracking_method): + config_path = TRACKER_SEARCH_SPACES / f"{tracking_method}.yaml" # Example: 'botsort_search_space.yaml' + with open(config_path, 'r') as file: + config = yaml.safe_load(file) + return config + + # Define the search space for hyperparameters -def get_search_space(tracking_method): - if tracking_method == 'strongsort': - search_space = { - "ema_alpha": tune.uniform(0.7, 0.95), - "max_cos_dist": tune.uniform(0.1, 0.4), - "max_iou_dist": tune.uniform(0.5, 0.95), - "max_age": tune.randint(10, 151), # The upper bound is exclusive in randint - "n_init": tune.randint(1, 4), # The upper bound is exclusive in randint - "mc_lambda": tune.uniform(0.90, 0.999), - "nn_budget": tune.choice([100]), - } - elif tracking_method == 'hybridsort': - search_space = { - "det_thresh": tune.uniform(0, 0.6), - "max_age": tune.randint(10, 151, 10), # The upper bound is exclusive in randint - "min_hits": tune.randint(1, 6), # The upper bound is exclusive in randint - "delta_t": tune.randint(1, 6), # The upper bound is exclusive in randint - "asso_func": tune.choice(['iou', 'giou', 'diou']), - "iou_thresh": tune.uniform(0.1, 0.4), - "inertia": tune.uniform(0.1, 0.4), - "TCM_first_step_weight": tune.uniform(0, 0.5), - "longterm_reid_weight": tune.uniform(0, 0.5), - "use_byte": tune.choice([True, False]) - } - elif tracking_method == 'botsort': - search_space = { - "track_high_thresh": tune.uniform(0.3, 0.7), - "track_low_thresh": tune.uniform(0.1, 0.3), - "new_track_thresh": tune.uniform(0.1, 0.8), - "track_buffer": tune.randint(20, 81, 10), # The upper bound is exclusive in randint - "match_thresh": tune.uniform(0.1, 0.9), - "proximity_thresh": tune.uniform(0.25, 0.75), - "appearance_thresh": tune.uniform(0.1, 0.8), - "cmc_method": tune.choice(['sparseOptFlow']), - "frame_rate": tune.choice([30]), - "lambda_": tune.uniform(0.97, 0.995) - } - elif tracking_method == 'bytetrack': - search_space = { - "track_thresh": tune.uniform(0.4, 0.6), - "track_buffer": tune.randint(10, 61, 10), # The upper bound is exclusive in randint - "match_thresh": tune.uniform(0.7, 0.9) - } - elif tracking_method == 'ocsort': - search_space = { - "det_thresh": tune.uniform(0, 0.6), - "max_age": tune.grid_search([10, 20, 30, 40, 50, 60]), # Since step is 10, using grid_search for these discrete values - "min_hits": tune.grid_search([1, 2, 3, 4, 5]), # Since step is 1, using grid_search for these discrete values - "delta_t": tune.grid_search([1, 2, 3, 4, 5]), # Since step is 1, using grid_search for these discrete values - "asso_func": tune.choice(['iou', 'giou', 'centroid']), - "use_byte": tune.choice([True, False]), - "inertia": tune.uniform(0.1, 0.4), - "Q_xy_scaling": tune.loguniform(0.01, 1), - "Q_s_scaling": tune.loguniform(0.0001, 1) - } - elif tracking_method == 'deepocsort': - search_space = { - "det_thresh": tune.uniform(0.3, 0.6), # Changed from int to uniform since it seems to be a float range - "max_age": tune.randint(10, 61, 10), # The upper bound is exclusive in randint - "min_hits": tune.randint(1, 6), # The upper bound is exclusive in randint - "iou_thresh": tune.uniform(0.1, 0.4), - "delta_t": tune.randint(1, 6), # The upper bound is exclusive in randint - "asso_func": tune.choice(['iou', 'giou']), - "inertia": tune.uniform(0.1, 0.4), - "w_association_emb": tune.uniform(0.5, 0.9), - "alpha_fixed_emb": tune.uniform(0.9, 0.999), - "aw_param": tune.uniform(0.3, 0.7), - "embedding_off": tune.choice([True, False]), - "cmc_off": tune.choice([True, False]), - "aw_off": tune.choice([True, False]), - "Q_xy_scaling": tune.uniform(0.01, 1), - "Q_s_scaling": tune.uniform(0.0001, 1) - } - elif tracking_method == 'imprassoc': - search_space = { - "track_high_thresh": tune.uniform(0.3, 0.7), - "track_low_thresh": tune.uniform(0.1, 0.3), - "new_track_thresh": tune.uniform(0.1, 0.8), - "track_buffer": tune.qrandint(20, 80, 10), # The upper bound is exclusive in randint - "match_thresh": tune.uniform(0.1, 0.9), - "second_match_thresh": tune.uniform(0.1, 0.4), - "overlap_thresh": tune.uniform(0.3, 0.6), - "proximity_thresh": tune.uniform(0.1, 0.8), - "appearance_thresh": tune.uniform(0.1, 0.8), - "cmc_method": tune.choice(['sparseOptFlow']), - "frame_rate": tune.choice([30]), - "lambda_": tune.uniform(0.97, 0.995) - } +def yaml_to_search_space(config): + search_space = {} + for param, details in config.items(): + search_type = details['type'] + if search_type == 'uniform': + search_space[param] = tune.uniform(*details['range']) + elif search_type == 'randint': + search_space[param] = tune.randint(*details['range']) + elif search_type == 'qrandint': + search_space[param] = tune.qrandint(*details['range']) + elif search_type == 'choice': + search_space[param] = tune.choice(details['options']) + elif search_type == 'grid_search': + search_space[param] = tune.grid_search(details['values']) + elif search_type == 'loguniform': + search_space[param] = tune.loguniform(*details['range']) return search_space + opt = parse_optt() opt.val_tools_path = EXAMPLES / 'val_utils' opt.source = Path(opt.source).resolve() opt.yolo_model = [Path(y).resolve() for y in opt.yolo_model] opt.reid_model = [Path(r).resolve() for r in opt.reid_model] -search_space = get_search_space(opt.tracking_method) + +# Load the appropriate YAML configuration +yaml_config = load_yaml_config(opt.tracking_method) + +# Convert YAML config to Ray Tune search space +search_space = yaml_to_search_space(yaml_config) + tracker = Tracker(opt, search_space) run_generate_dets_embs(opt)