Skip to content

Tune Trackers

Use Optuna to tune tracker hyperparameters automatically and maximize your target metric on MOT-format evaluation data.

What you'll learn:

  • Install tuning dependencies
  • Prepare ground truth and detection files for tuning
  • Run tuning from CLI and Python
  • Save and apply the best parameter set

Install

Install the tuning extra to enable Optuna-based hyperparameter search.

pip install "trackers[tune]"

For more options, see the install guide.


Prepare Data

The tuner needs matching MOT files for ground truth and detections.

By default, the first trial evaluates a baseline parameter set before Optuna samples further combinations. That trial counts toward --n-trials / n_trials. Set enqueue_defaults=False on Tuner to disable this behavior.

For each search_space key, the baseline uses the tracker's default when it lies within the search space.

Options that are not tuned (or differ from __init__) are set with fixed_params on Tuner. They apply to every trial, including the baseline, override the same key in search_space if present, and are returned from run() merged into the best parameter dict.

Use fixed_defaults to hold named parameters at their tracker constructor defaults without copying their values. These parameters are also excluded from the search and returned with the best parameters. If a name appears in both, its explicit fixed_params value wins.

from trackers.tune import Tuner

# Detection-only BoTSORT (no frames, CMC off)
tuner = Tuner(
    tracker_id="botsort",
    gt_dir="./data/gt",
    detections_dir="./data/detections",
    fixed_params={"enable_cmc": False},
    n_trials=50,
)

# BoTSORT with CMC (MOT-style images required)
tuner = Tuner(
    tracker_id="botsort",
    gt_dir="./data/gt",
    detections_dir="./data/detections",
    images_dir="./data/images",
    fixed_params={"enable_cmc": True},
    n_trials=50,
)
trackers tune \
    --tracker botsort \
    --gt_dir ./data/gt \
    --detections_dir ./data/detections \
    --fixed_params '{"enable_cmc": false}'

Images are read from {images_dir}/{sequence}/img1/ using MOT-style stems: 6-digit (000001.jpg, MOT17/SportsMOT) or 8-digit (00000001.jpg, DanceTrack), plus common extensions (.jpg, .png, …).

data
├── gt
│   ├── MOT17-02-FRCNN.txt
│   ├── MOT17-04-FRCNN.txt
│   └── ...
└── detections
    ├── MOT17-02-FRCNN.txt
    ├── MOT17-04-FRCNN.txt
    └── ...

Each sequence must exist in both directories with the same filename ({sequence}.txt).

Use MOT format lines:

<frame>,<id>,<bb_left>,<bb_top>,<bb_width>,<bb_height>,<conf>,<x>,<y>,<z>

For detections, use id=-1. For more details on the format and evaluation workflow, see the evaluation guide.


Quickstart

Tune ByteTrack and optimize HOTA.

trackers tune \
    --tracker bytetrack \
    --gt_dir ./data/gt \
    --detections_dir ./data/detections \
    --objective HOTA \
    --metrics '[CLEAR,HOTA,Identity]' \
    --n_trials 50 \
    --output ./results/bytetrack-best.json

Run the same tuning flow with the Tuner class.

from trackers.tune import Tuner

tuner = Tuner(
    tracker_id="bytetrack",
    gt_dir="./data/gt",
    detections_dir="./data/detections",
    objective="HOTA",
    metrics=["CLEAR", "HOTA", "Identity"],
    n_trials=50,
    seed=42,
)

best_params = tuner.run()
print(best_params)

Tune a Sequence Subset

Use a seqmap file when you want to tune on a specific subset of sequences.

# seqmap.txt
MOT17-02-FRCNN
MOT17-04-FRCNN
MOT17-09-FRCNN
trackers tune \
    --tracker bytetrack \
    --gt_dir ./data/gt \
    --detections_dir ./data/detections \
    --seqmap ./seqmap.txt
from trackers.tune import Tuner

tuner = Tuner(
    tracker_id="bytetrack",
    gt_dir="./data/gt",
    detections_dir="./data/detections",
    seqmap="./seqmap.txt",
    n_trials=25,
)

best_params = tuner.run()
print(best_params)

Tune ReID Thresholds

Pass an encoder to BoT-SORT and the search adds reid_config.appearance_threshold and reid_config.proximity_threshold. Tune the two together: a looser proximity gate usually needs a stricter appearance threshold. To search only these two, hold the other search parameters at BoT-SORT's constructor defaults with fixed_defaults. images_dir is required, because the encoder reads the frames.

Every trial replays the same detections, so cache_embeddings=True embeds each one once and reuses it, which saves most of a study's time. The embeddings then stay in memory for the whole study, about 1 GB per 500k detections, which is why it is off by default.

trackers tune \
    --tracker botsort \
    --gt_dir ./data/gt \
    --detections_dir ./data/detections \
    --images_dir ./data/images \
    --reid.model fastreid_mot17_sbs50 \
    --fixed_defaults '["lost_track_buffer", "minimum_consecutive_frames", "minimum_iou_threshold_first_assoc", "minimum_iou_threshold_second_assoc", "minimum_iou_threshold_unconfirmed_assoc", "high_conf_det_threshold", "track_activation_threshold", "cmc_downscale"]' \
    --n_trials 20
from trackers.tune import Tuner

motion_defaults = [
    "lost_track_buffer",
    "minimum_consecutive_frames",
    "minimum_iou_threshold_first_assoc",
    "minimum_iou_threshold_second_assoc",
    "minimum_iou_threshold_unconfirmed_assoc",
    "high_conf_det_threshold",
    "track_activation_threshold",
    "cmc_downscale",
]

tuner = Tuner(
    tracker_id="botsort",
    gt_dir="./data/gt",
    detections_dir="./data/detections",
    images_dir="./data/images",
    fixed_params={"reid_model": "fastreid_mot17_sbs50"},
    fixed_defaults=motion_defaults,
    n_trials=20,
    cache_embeddings=True,
)
best_params = tuner.run()

With the cache on, each detection is embedded once and reused by later trials, so the first trial is the slow one. The Python result contains a ReIDConfig object and can be passed directly to BoTSORTTracker. When loading saved JSON, construct ReIDConfig(**best_params["reid_config"]) before unpacking it into the tracker.


Use Best Parameters

Apply tuned values by unpacking the saved JSON dictionary into your tracker constructor.

import json

from trackers import ByteTrackTracker

with open("./results/bytetrack-best.json", "r", encoding="utf-8") as f:
    best_params = json.load(f)

tracker = ByteTrackTracker(**best_params)

CLI Reference

All arguments accepted by trackers tune.

Argument Description Default
--tracker Tracker name to tune. Common values: bytetrack, sort, ocsort. —
--gt_dir Directory with ground-truth MOT files ({sequence}.txt). —
--detections_dir Directory with detection MOT files ({sequence}.txt), one file per sequence. —
--objective Metric to maximize: MOTA, HOTA, or IDF1. HOTA
--n_trials Number of Optuna trials to run. 100
--fixed_params Tracker constructor kwargs held constant across every trial (JSON object). Applied on top of, and taking priority over, any overlapping search_space key; also merged into the returned best-parameter dict. None
--fixed_defaults Tracker constructor parameter names held at their defaults across every trial (JSON list). Explicit fixed_params values take priority. None
--images_dir MOT-style image root for frame-based features such as CMC. Frames are read from {images_dir}/{sequence}/img1/. None
--reid.model ReID encoder for BoT-SORT: alias, hf:// or http(s):// URL, or local path. See the reid loading guide for more. Adds reid_config.appearance_threshold and reid_config.proximity_threshold to the search. Requires --images_dir. Also accepts --reid.device and --reid.architecture. None
--search_space Search-space entries that replace or extend the tracker's own for this run (JSON object, same format as the tracker's search_space). None
--enqueue_defaults Evaluate the tracker's default parameters as the first trial before Optuna sampling begins. Negate with --no_enqueue_defaults. true
--metrics Metric families to compute: CLEAR, HOTA, Identity. The family required by --objective is added automatically. CLEAR
--threshold IoU threshold used during evaluation matching for CLEAR and Identity. Higher values make scoring stricter, lower values make it more permissive. 0.5
--seqmap Optional path to a sequence map file. When set, only listed sequences are tuned. all files in --detections_dir
--seed Random seed for Optuna's TPE sampler (reproducible sampled trials). None
--output Path to save best parameters as JSON. None