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.
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,
)
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:
For detections, use id=-1. For more details on the format and evaluation workflow, see the evaluation guide.
Quickstart
Tune ByteTrack and optimize HOTA.
Tune a Sequence Subset
Use a seqmap file when you want to tune on a specific subset of sequences.
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 |