Skip to content

Commit 5d61be1

Browse files
Bordaclaude
andcommitted
docs(program.md): remove tried/reverted tables and key-lesson verdicts
Keep "already in the code" tables (prevent duplicate work) but strip dataset-specific verdicts that anchor future agents against valid hypotheses: - ByteTrack Phase 1 "tried and reverted" block removed - SORT Phase 1 "tried and reverted" sub-section removed - OC-SORT Phase 1 "Optuna findings" paragraph removed Full campaign history remains in autotune/README.md Journal section. --- Co-authored-by: Claude Code <noreply@anthropic.com>
1 parent d824e44 commit 5d61be1

6 files changed

Lines changed: 80 additions & 97 deletions

File tree

autotune/best_config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,4 +261,4 @@
261261
}
262262
}
263263
}
264-
}
264+
}

autotune/default_config.json

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,56 @@
11
{
2-
"_comment": "Default tracker parameters used for baseline evaluation (--n-trials 1).",
3-
"_edit_here": "Edit this file to change defaults. Do not hard-code values in optimize_tracking.py.",
4-
"bytetrack": {
5-
"lost_track_buffer": 57,
6-
"track_activation_threshold": 0.3328,
7-
"minimum_consecutive_frames": 1,
8-
"minimum_iou_threshold": 0.146,
9-
"stage2_iou_threshold": 0.2999,
10-
"iou_age_weight": 0.07197,
11-
"high_conf_det_threshold": 0.7952,
12-
"q_scale": 0.003,
13-
"r_scale": 0.5762,
14-
"p_scale": 2.5,
15-
"velocity_decay": 0.82,
16-
"q_miss_alpha": 0.7961,
17-
"max_interpolation_gap": 48,
18-
"p_reset_threshold": 12,
19-
"oru_threshold": 0,
20-
"conf_cost_weight": 0.1696,
21-
"stage2_min_updates": 12,
22-
"giou_blend": 0.42
23-
},
24-
"sort": {
25-
"lost_track_buffer": 26,
26-
"track_activation_threshold": 0.9725,
27-
"minimum_consecutive_frames": 1,
28-
"minimum_iou_threshold": 0.275,
29-
"max_interpolation_gap": 57,
30-
"velocity_decay": 0.82,
31-
"q_miss_alpha": 0.8,
32-
"p_reset_threshold": 10,
33-
"oru_threshold": 3,
34-
"conf_cost_weight": 0.2,
35-
"iou_age_weight": 0.0,
36-
"high_conf_det_threshold": 0.0,
37-
"stage2_iou_threshold": 0.05
38-
},
39-
"ocsort": {
40-
"lost_track_buffer": 74,
41-
"minimum_consecutive_frames": 1,
42-
"minimum_iou_threshold": 0.1487990736044123,
43-
"direction_consistency_weight": 0.0006177923357997676,
44-
"high_conf_det_threshold": 0.6875834299207869,
45-
"delta_t": 1,
46-
"max_interpolation_gap": 42,
47-
"q_scale": 0.7203257524174236,
48-
"r_scale": 1.1889118447922835,
49-
"p_scale": 0.09520352672425254,
50-
"conf_cost_weight": 0.9698770881869533,
51-
"iou_age_weight": 0.42792379789381346,
52-
"p_reset_threshold": 8,
53-
"velocity_decay": 0.9259939633989623,
54-
"q_miss_alpha": 0.5122722647370503
55-
}
2+
"_comment": "Default tracker parameters used for baseline evaluation (--n-trials 1).",
3+
"_edit_here": "Edit this file to change defaults. Do not hard-code values in optimize_tracking.py.",
4+
"bytetrack": {
5+
"lost_track_buffer": 57,
6+
"track_activation_threshold": 0.3328,
7+
"minimum_consecutive_frames": 1,
8+
"minimum_iou_threshold": 0.146,
9+
"stage2_iou_threshold": 0.2999,
10+
"iou_age_weight": 0.07197,
11+
"high_conf_det_threshold": 0.7952,
12+
"q_scale": 0.003,
13+
"r_scale": 0.5762,
14+
"p_scale": 2.5,
15+
"velocity_decay": 0.82,
16+
"q_miss_alpha": 0.7961,
17+
"max_interpolation_gap": 48,
18+
"p_reset_threshold": 12,
19+
"oru_threshold": 0,
20+
"conf_cost_weight": 0.1696,
21+
"stage2_min_updates": 12,
22+
"giou_blend": 0.42
23+
},
24+
"sort": {
25+
"lost_track_buffer": 26,
26+
"track_activation_threshold": 0.9725,
27+
"minimum_consecutive_frames": 1,
28+
"minimum_iou_threshold": 0.275,
29+
"max_interpolation_gap": 57,
30+
"velocity_decay": 0.82,
31+
"q_miss_alpha": 0.8,
32+
"p_reset_threshold": 10,
33+
"oru_threshold": 3,
34+
"conf_cost_weight": 0.2,
35+
"iou_age_weight": 0.0,
36+
"high_conf_det_threshold": 0.0,
37+
"stage2_iou_threshold": 0.05
38+
},
39+
"ocsort": {
40+
"lost_track_buffer": 74,
41+
"minimum_consecutive_frames": 1,
42+
"minimum_iou_threshold": 0.1487990736044123,
43+
"direction_consistency_weight": 0.0006177923357997676,
44+
"high_conf_det_threshold": 0.6875834299207869,
45+
"delta_t": 1,
46+
"max_interpolation_gap": 42,
47+
"q_scale": 0.7203257524174236,
48+
"r_scale": 1.1889118447922835,
49+
"p_scale": 0.09520352672425254,
50+
"conf_cost_weight": 0.9698770881869533,
51+
"iou_age_weight": 0.42792379789381346,
52+
"p_reset_threshold": 8,
53+
"velocity_decay": 0.9259939633989623,
54+
"q_miss_alpha": 0.5122722647370503
55+
}
5656
}

autotune/guard.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,34 @@
1+
# ------------------------------------------------------------------------
2+
# Trackers
3+
# Copyright (c) 2026 Roboflow. All Rights Reserved.
4+
# Licensed under the Apache License, Version 2.0 [see LICENSE for details]
5+
# ------------------------------------------------------------------------
6+
17
"""Regression guard: ensures no tracker's HOTA drops >0.5% from the stored best."""
28

39
import json
410
import re
5-
import subprocess
611
import sys
12+
from contextlib import redirect_stdout
13+
from io import StringIO
14+
from pathlib import Path
15+
16+
from optimize_tracking import main as optimize_tracking_main
17+
18+
19+
def _run_search(tracker_name: str) -> str:
20+
"""Run tracker optimization and return captured stdout."""
21+
stdout_buffer = StringIO()
22+
with redirect_stdout(stdout_buffer):
23+
optimize_tracking_main(tracker=tracker_name, det_source="sdp", n_trials=500)
24+
return stdout_buffer.getvalue()
25+
726

8-
best = json.load(open("best_config.json"))
27+
best = json.loads((Path(__file__).parent / "best_config.json").read_text())
928
failed = []
1029

1130
for t in ["bytetrack", "sort", "ocsort"]:
12-
out = subprocess.run(
13-
["uv", "run", "python", "optimize_tracking.py", t, "sdp", "--n-trials", "500"],
14-
capture_output=True,
15-
text=True,
16-
).stdout
31+
out = _run_search(t)
1732
m = re.search(r"HOTA=([0-9.]+)", out)
1833
if not m:
1934
failed.append(f"{t}: no HOTA output")

autotune/program.md

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -129,20 +129,6 @@ These hypotheses were implemented and kept in ByteTrack Phase 1. They are **not
129129
| Post-processing gap interpolation (max_gap=20) | +1.666% |
130130
| P reset on re-detection after occlusion | +1.674% |
131131

132-
### ByteTrack Phase 1 — tried and reverted (likely to regress for any tracker)
133-
134-
| Hypothesis | Outcome |
135-
| -------------------------------------------- | ----------------------------------------------- |
136-
| Non-uniform P init (pos/vel split) | Both regressions on ByteTrack |
137-
| Size-adaptive R (area scaling) | Regression |
138-
| NSA Kalman confidence-gated R | Regression |
139-
| Two-stage IoU threshold (Stage 1 ≠ Stage 2) | Both regressions on ByteTrack |
140-
| Immature track grace period (1 missed frame) | Regression |
141-
| Joseph-form covariance update | No change (algebraically equivalent at float32) |
142-
| Two-hit birth policy | Regression |
143-
| Per-axis velocity decay (pos/size split) | Regression |
144-
| Velocity-only Q inflation | No change |
145-
146132
### Research starting points — SOTA-inspired, not yet tried on all trackers
147133

148134
Provided as inspiration, not a prescribed order. Hypotheses apply to the active `{algo}` tracker unless noted.
@@ -183,16 +169,6 @@ Campaign run on `bemch/auto-research` using 3-team parallel strategy (Kalman / A
183169

184170
**New SORT constructor params**: `velocity_decay`, `q_miss_alpha`, `p_reset_threshold`, `oru_threshold`, `conf_cost_weight`, `iou_age_weight`, `high_conf_det_threshold`, `stage2_iou_threshold`
185171

186-
#### Tried and reverted
187-
188-
| Hypothesis | Outcome |
189-
| ------------------------------------------------------- | ---------- |
190-
| xcycsr Kalman state representation | −0.51% |
191-
| Velocity-adaptive Q scaling | −0.06% |
192-
| Mahalanobis distance gate | Regression |
193-
| GIoU as association metric | Regression |
194-
| OC-SORT velocity correction (duplicate, second attempt) | Reverted |
195-
196172
#### Tuned best config (sort/sdp, 500 trials)
197173

198174
```json
@@ -229,8 +205,6 @@ Campaign run on `bemch/auto-research` using 3-team parallel strategy (Kalman / A
229205
| P reset to identity on re-detection after gap (p_reset_threshold) | `9960dd5` | enables Optuna headroom |
230206
| Velocity decay + Q inflation during missed frames (velocity_decay, q_miss_alpha) | `9525885` | +0.43% to HOTA 58.905 |
231207

232-
**Optuna findings**: `direction_consistency_weight` converged near-zero (0.0006) — OCM direction signal hurts on SDP; `conf_cost_weight` converged high (0.97); `iou_age_weight` = 0.43 is effective; `velocity_decay` = 0.926 + `q_miss_alpha` = 0.512 reduce prediction drift.
233-
234208
**New OC-SORT constructor params**: `conf_cost_weight`, `iou_age_weight`, `p_reset_threshold`, `velocity_decay`, `q_miss_alpha`
235209

236210
#### Tuned best config (ocsort/sdp, 500 trials, HOTA=58.905)

trackers/core/sort/kalman.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,7 @@ def update(self, bbox: NDArray[np.float64]) -> None:
170170
and self._last_observed_bbox is not None
171171
):
172172
bbox_f = bbox.astype(np.float32)
173-
virtual_vel = (
174-
(bbox_f[:4] - self._last_observed_bbox) / was_lost_for
175-
)
173+
virtual_vel = (bbox_f[:4] - self._last_observed_bbox) / was_lost_for
176174
self.state[4, 0] = virtual_vel[0]
177175
self.state[5, 0] = virtual_vel[1]
178176
self.state[6, 0] = virtual_vel[2]

trackers/core/sort/utils.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,7 @@ def get_alive_trackers(
5050
return alive_trackers
5151

5252

53-
def _compute_diou_matrix(
54-
boxes_a: np.ndarray, boxes_b: np.ndarray
55-
) -> np.ndarray:
53+
def _compute_diou_matrix(boxes_a: np.ndarray, boxes_b: np.ndarray) -> np.ndarray:
5654
"""Compute Distance IoU (DIoU) between two sets of boxes.
5755
5856
DIoU = IoU - d^2 / c^2 where d is the Euclidean distance between box
@@ -74,9 +72,7 @@ def _compute_diou_matrix(
7472
x2_inter = np.minimum(boxes_a[:, 2:3], boxes_b[:, 2:3].T)
7573
y2_inter = np.minimum(boxes_a[:, 3:4], boxes_b[:, 3:4].T)
7674

77-
inter_area = np.maximum(x2_inter - x1_inter, 0) * np.maximum(
78-
y2_inter - y1_inter, 0
79-
)
75+
inter_area = np.maximum(x2_inter - x1_inter, 0) * np.maximum(y2_inter - y1_inter, 0)
8076

8177
# Areas of individual boxes
8278
area_a = (

0 commit comments

Comments
 (0)