diff --git a/README.md b/README.md index b3c567bda..6e8a99460 100644 --- a/README.md +++ b/README.md @@ -83,20 +83,23 @@ For all CLI options, see the [tracking guide](https://trackers.roboflow.com/deve ## Algorithms -Each tracker below is a faithful implementation of its original paper's motion and association pipeline; appearance/ReID branches are not included where papers offer them — see each tracker's docs page for the exact scope. Pick the one that fits your scene, or run the benchmark to find out which performs best on your data. +Each tracker below is a faithful implementation of its original paper's motion and association pipeline; appearance/ReID branches are off by default, though BoT-SORT accepts one through `reid_model` (see the [ReID guide](https://trackers.roboflow.com/latest/guides/reid/)). Each tracker's docs page states the exact scope. Pick the one that fits your scene, or run the benchmark to find out which performs best on your data. - + -| Algorithm | Description | MOT17 HOTA | SportsMOT HOTA | SoccerNet HOTA | DanceTrack HOTA | -| :-------------------------------------------: | :------------------------------------------------------------------------------: | :--------: | :------------: | :------------: | :-------------: | -| [SORT](https://arxiv.org/abs/1602.00763) | Kalman filter + Hungarian matching baseline. | 58.4 | 70.8 | 81.6 | 47.2 | -| [ByteTrack](https://arxiv.org/abs/2110.06864) | Two-stage association using high and low confidence detections. | 60.1 | 73.0 | 84.0 | 53.3 | -| [OC-SORT](https://arxiv.org/abs/2203.14360) | Observation-centric recovery for lost tracks. | 61.9 | 71.7 | 78.4 | 54.1 | -| [BoT-SORT](https://arxiv.org/abs/2206.14651) | Camera motion compensation. | 63.7 | 73.8 | 84.5 | 57.8 | -| [C-BIoU](https://arxiv.org/abs/2211.14317) | Cascaded buffered IoU matching for fast or irregular motion. | 63.0 | 73.1 | 82.6 | 56.7 | -| [McByte](https://arxiv.org/abs/2506.01373) | Mask-conditioned tracking — adds propagated SAM/Cutie masks as a matching cue.\* | **64.1** | **76.5** | **85.0** | **67.2** | +| Algorithm | Description | MOT17 HOTA | SportsMOT HOTA | SoccerNet HOTA | DanceTrack HOTA | +| :-------------------------------------------------------------------: | :--------------------------------------------------------------------------------: | :--------: | :------------: | :------------: | :-------------: | +| [SORT](https://arxiv.org/abs/1602.00763) | Kalman filter + Hungarian matching baseline. | 58.4 | 70.8 | 81.6 | 47.2 | +| [ByteTrack](https://arxiv.org/abs/2110.06864) | Two-stage association using high and low confidence detections. | 60.1 | 73.0 | 84.0 | 53.3 | +| [OC-SORT](https://arxiv.org/abs/2203.14360) | Observation-centric recovery for lost tracks. | 61.9 | 71.7 | 78.4 | 54.1 | +| [C-BIoU](https://arxiv.org/abs/2211.14317) | Cascaded buffered IoU matching for fast or irregular motion. | 63.0 | 73.1 | 82.6 | 56.7 | +| [BoT-SORT](https://arxiv.org/abs/2206.14651) | Camera motion compensation. | 63.7 | 73.8 | 84.5 | 57.8 | +| [BoT-SORT + ReID](https://trackers.roboflow.com/develop/guides/reid/) | Appearance embeddings fused with motion, for harder association.\* | 63.9 | 75.5 | 84.3 | 57.0 | +| [McByte](https://arxiv.org/abs/2506.01373) | Mask-conditioned tracking — adds propagated SAM/Cutie masks as a matching cue.\*\* | **64.1** | **76.5** | **85.0** | **67.2** | -\*McByte needs optional heavyweight deps (`torch`, SAM, Cutie) not installed by default. It tops HOTA on all four benchmarks above — see the [McByte docs](https://trackers.roboflow.com/develop/trackers/mcbyte/) for setup. +\*BoT-SORT + ReID is listed with library default parameters and the default encoder `fastreid_mot17_sbs50` (BoT-SORT's own ReID model, trained on MOT17) on all four datasets. At its best tuned configuration on each dataset, it reaches 64.6 (MOT17), 77.8 (SportsMOT), 88.4 (SoccerNet) and 60.8 (DanceTrack) HOTA on the test sets, above BoT-SORT without ReID on all four. See the [ReID guide](https://trackers.roboflow.com/develop/guides/reid/). + +\*\*McByte needs optional heavyweight deps (`torch`, SAM, Cutie) not installed by default. It tops HOTA on all four benchmarks above. See the [McByte docs](https://trackers.roboflow.com/develop/trackers/mcbyte/) for setup. All scores use default parameters on the standard split. Detections come from a YOLOX detector (MOT17, SportsMOT, DanceTrack) or oracle ground-truth boxes (SoccerNet) — absolute numbers shift with detector quality. See the [tracker comparison](https://trackers.roboflow.com/develop/evaluations/results/) for tuned numbers and methodology. diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 757b481cd..91a46ae4b 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -10,7 +10,8 @@ comment) and update every listed sibling. If you change a cell somewhere else fi it's the source of truth, not just another copy. Discover live: grep -rn BENCH-XREF docs/ README.md -(15 xref comments as of 2026-08-12: 5 in results.md, 6 in docs/trackers/*.md, 3 in docs/index.md, 1 in README.md. +(20 xref comments as of 2026-09-28: 9 in results.md, 6 in docs/trackers/*.md, 3 in docs/index.md, 1 in README.md, + 1 in docs/guides/reid.md. A 16th lived in .github/copilot-instructions.md until 2026-08-12, when that file was deleted and its guidance merged into the root AGENTS.md — which deliberately carries NO benchmark table. Don't add one there.) @@ -19,7 +20,10 @@ Discover live: grep -rn BENCH-XREF docs/ README.md - id=sportsmot-default (## SportsMOT -> === "Default") - id=soccernet-default (## SoccerNet-tracking -> === "Default") - id=dancetrack-default (## DanceTrack -> === "Default") -- Tuned tables (all 4 benchmarks) have NO external duplicates — only referenced from within results.md itself. +- id=mot17-tuned, id=sportsmot-tuned, id=soccernet-tuned, id=dancetrack-tuned (=== "Tuned" tabs). Their BoT-SORT + rows are copied into [guides/reid.md](guides/reid.md) (Results, both tabs). Their BoT-SORT + ReID rows run the + other way: copied FROM guides/reid.md (the best test row across its two tabs), and their HOTA also appears in + the BoT-SORT + ReID footnote of index.md and README.md. ## Duplicate sites, per canonical row @@ -46,8 +50,8 @@ BoT-SORT row (mot17/sportsmot/soccernet/dancetrack): C-BIoU row (mot17/sportsmot/soccernet/dancetrack — the only tracker doc with a DanceTrack row): -> [trackers/cbiou.md](trackers/cbiou.md) (table, full row, all 4 benchmarks) + -> [index.md](index.md) (Algorithms table, HOTA column only) -> [../README.md](../README.md) (Algorithms table, HOTA column only) - -> docs/index.md does NOT have a C-BIoU row — don't add one when editing, that's existing scope, not a gap. McByte row (mot17/sportsmot/soccernet/dancetrack): -> [trackers/mcbyte.md](trackers/mcbyte.md) (McByte row, matching benchmark tab, full row) @@ -55,11 +59,16 @@ McByte row (mot17/sportsmot/soccernet/dancetrack): -> [../README.md](../README.md) (Algorithms table, HOTA column only; includes C-BIoU row too) — the index.md FAQ claim above is TRUE only while McByte is bolded-best in all 4 Default tables. Re-verify, don't assume. +BoT-SORT + ReID row (mot17/sportsmot/soccernet/dancetrack; Default = `fastreid_mot17_sbs50` at library defaults): + -> [index.md](index.md) (Algorithms table, HOTA column only) + -> [../README.md](../README.md) (Algorithms table, HOTA column only) + -> [guides/reid.md](guides/reid.md) is where the Tuned ReID rows come FROM, see Canonical tables above. + ## Structural asymmetries (intentional — do not "fix" by adding rows) - docs/trackers/{sort,bytetrack,ocsort,botsort}.md tables cover MOT17/SportsMOT/SoccerNet only, no DanceTrack row. - docs/trackers/cbiou.md is the only individual-tracker doc with a DanceTrack row. -- docs/index.md Algorithms table has 5 tracker rows (SORT/ByteTrack/OC-SORT/BoT-SORT/McByte), no C-BIoU row. -- README.md Algorithms table has 6 tracker rows (SORT/ByteTrack/OC-SORT/BoT-SORT/C-BIoU/McByte). +- docs/index.md and README.md Algorithms tables have the same 7 rows, in the same order as the results.md tables: + SORT/ByteTrack/OC-SORT/C-BIoU/BoT-SORT/BoT-SORT + ReID/McByte. - The root AGENTS.md carries NO benchmark table — it links to evaluations/results.md. That is deliberate; don't add a table back (it replaced .github/copilot-instructions.md, deleted 2026-08-12, which had one). - docs/trackers/mcbyte.md reports McByte vs a BoT-SORT baseline only (not vs SORT/ByteTrack/OC-SORT/C-BIoU). diff --git a/docs/assets/reid/soccernet-osnet-appearance-distances-vs-gap.png b/docs/assets/reid/soccernet-osnet-appearance-distances-vs-gap.png deleted file mode 100644 index 75dd587e1..000000000 Binary files a/docs/assets/reid/soccernet-osnet-appearance-distances-vs-gap.png and /dev/null differ diff --git a/docs/assets/reid/soccernet-osnet-appearance-distances.png b/docs/assets/reid/soccernet-osnet-appearance-distances.png deleted file mode 100644 index 61858b26d..000000000 Binary files a/docs/assets/reid/soccernet-osnet-appearance-distances.png and /dev/null differ diff --git a/docs/evaluations/results.md b/docs/evaluations/results.md index d44e88778..8de10aa0a 100644 --- a/docs/evaluations/results.md +++ b/docs/evaluations/results.md @@ -5,11 +5,11 @@ description: Side-by-side MOT benchmark comparison of SORT, ByteTrack, OC-SORT, # Tracker Comparison -This page shows head-to-head performance of SORT, ByteTrack, OC-SORT, BoT-SORT, C-BIoU, and McByte on standard MOT benchmarks. Results are shown with default parameters and with parameter-tuned configurations found via grid search. McByte is reported at default parameters only (mask-conditioned association enabled); it is designed to require no per-dataset tuning, so there is no Tuned row. +This page shows head-to-head performance of SORT, ByteTrack, OC-SORT, C-BIoU, BoT-SORT, and McByte on standard MOT benchmarks. Results are shown with default parameters and with parameter-tuned configurations found via grid search. McByte is reported at default parameters only (mask-conditioned association enabled); it is designed to require no per-dataset tuning, so there is no Tuned row. BoT-SORT + ReID is shown at library defaults in the Default tabs, with the default encoder `fastreid_mot17_sbs50` throughout; its Tuned rows show the best test result among the configurations in the [ReID guide](../guides/reid.md#results), each with an encoder trained on that dataset: `osnet_x1_0` fine-tuned on the SportsMOT, SoccerNet and DanceTrack train splits, and on MOT17 `fastreid_mot17_sbs50`, which the BoT-SORT authors trained on MOT17. !!! info "Benchmark version" - Results use **trackers v2.6.0** (released 2026-08-03). Detections are from YOLOX (MOT17, SportsMOT, DanceTrack) or ground-truth oracle boxes (SoccerNet). Parameters were tuned via grid search on held-out splits. See [Methodology](methodology.md) for details. + Results use **trackers v2.6.0** (released 2026-08-03), except the BoT-SORT + ReID rows, which were produced in v2.7.0, the release that adds appearance association. Detections are from YOLOX (MOT17, SportsMOT, DanceTrack) or ground-truth oracle boxes (SoccerNet). Parameters were tuned via grid search on held-out splits, and the ReID thresholds with [`trackers tune`](../guides/tune.md#tune-reid-thresholds). See [Methodology](methodology.md) for details. v2.6.0 changed all trackers' lost-track lifecycle from exclusive (`time_since_update < maximum_frames_without_update`) to inclusive (`<=`) boundary semantics, so confirmed tracks now survive one additional missed frame. Expect small IDSW/HOTA shifts versus earlier versions even for trackers whose parameters didn't change — see the [Changelog](../changelog.md) for details. @@ -28,43 +28,52 @@ Pedestrian tracking with crowded scenes and frequent occlusions. Strongly tests !!! info - Parameters were tuned on the validation set. Results are reported on the test set via Codabench submission. Detections come from a YOLOX model. BoT-SORT rows are CMC without appearance; see the [ReID guide](../guides/reid.md) for appearance association. + Parameters were tuned on the validation set. Results are reported on the test set via Codabench submission. Detections come from a YOLOX model. The BoT-SORT row is geometry and CMC only; BoT-SORT + ReID adds the encoder named under the table. The [ReID guide](../guides/reid.md#results) carries both fusion methods and the generic and fine-tuned encoders side by side. === "Default" - Results using default tracker parameters. + Results using default tracker parameters. The ReID row is BoT-SORT at library defaults with the default `fastreid_mot17_sbs50` encoder, BoT-SORT's own ReID model trained on MOT17 pedestrian crops (see [encoders](../guides/reid.md#choosing-an-encoder)). - | Tracker | HOTA | IDF1 | MOTA | - | :-------: | :------: | :------: | :------: | - | SORT | 58.4 | 69.9 | 67.2 | - | ByteTrack | 60.1 | 73.2 | 74.1 | - | OC-SORT | 61.9 | 76.4 | 76.0 | - | BoT-SORT | 63.7 | 78.7 | **79.2** | - | C-BIoU | 63.0 | 79.1 | 77.4 | - | McByte | **64.1** | **79.7** | 79.1 | + | Tracker | HOTA | IDF1 | MOTA | + | :-------------: | :------: | :------: | :------: | + | SORT | 58.4 | 69.9 | 67.2 | + | ByteTrack | 60.1 | 73.2 | 74.1 | + | OC-SORT | 61.9 | 76.4 | 76.0 | + | C-BIoU | 63.0 | 79.1 | 77.4 | + | BoT-SORT | 63.7 | 78.7 | **79.2** | + | BoT-SORT + ReID | 63.9 | 78.9 | **79.2** | + | McByte | **64.1** | **79.7** | 79.1 | === "Tuned" Results after grid search over tracker parameters. - | Tracker | HOTA | IDF1 | MOTA | - | :-------: | :------: | :------: | :------: | - | SORT | 60.4 | 72.5 | 75.8 | - | ByteTrack | 60.5 | 72.7 | 76.1 | - | OC-SORT | 62.0 | 76.5 | 77.3 | - | BoT-SORT | **63.8** | 78.7 | **79.4** | - | C-BIoU | 63.0 | **79.1** | 77.4 | + | Tracker | HOTA | IDF1 | MOTA | + | :-------------: | :------: | :------: | :------: | + | SORT | 60.4 | 72.5 | 75.8 | + | ByteTrack | 60.5 | 72.7 | 76.1 | + | OC-SORT | 62.0 | 76.5 | 77.3 | + | C-BIoU | 63.0 | 79.1 | 77.4 | + | BoT-SORT | 63.8 | 78.7 | **79.4** | + | BoT-SORT + ReID | **64.6** | **79.9** | **79.4** | - Tuned configuration for each tracker. + + + Tuned configuration for each tracker. The ReID row uses `fastreid_mot17_sbs50`, trained on MOT17 by the BoT-SORT authors, with `reid_config.fusion="adaptive"`: the best MOT17 test result in the [ReID guide](../guides/reid.md#results). It was chosen on test; on val-half, `botsort` scored 0.10 higher. ```yaml SORT: @@ -109,6 +118,15 @@ Pedestrian tracking with crowded scenes and frequent occlusions. Strongly tests track_activation_threshold: 0.7 buffer_ratio_first: 0.3 buffer_ratio_second: 0.5 + + BoT-SORT + ReID: + reid_model: fastreid_mot17_sbs50 + reid_config.fusion: adaptive + reid_config.appearance_weight: 1.908 + reid_config.adaptive_weight_cap: 0.545 + reid_config.appearance_floor: 0.381 + reid_config.proximity_threshold: 0.772 + minimum_iou_threshold_first_assoc: 0.846 ``` ## [SportsMOT](https://arxiv.org/abs/2304.05170) @@ -126,39 +144,48 @@ Sports broadcast tracking with fast motion, camera pans, and similar-looking tar === "Default" - Results using default tracker parameters. + Results using default tracker parameters. The ReID row is BoT-SORT at library defaults with the default `fastreid_mot17_sbs50` encoder, BoT-SORT's own ReID model trained on MOT17 pedestrian crops (see [encoders](../guides/reid.md#choosing-an-encoder)). - | Tracker | HOTA | IDF1 | MOTA | - | :-------: | :------: | :------: | :------: | - | SORT | 70.8 | 68.9 | 95.5 | - | ByteTrack | 73.0 | 72.5 | 96.4 | - | OC-SORT | 71.7 | 71.4 | 95.0 | - | BoT-SORT | 73.8 | 73.4 | 96.9 | - | C-BIoU | 73.1 | 72.6 | 96.7 | - | McByte | **76.5** | **76.9** | **97.0** | + | Tracker | HOTA | IDF1 | MOTA | + | :-------------: | :------: | :------: | :------: | + | SORT | 70.8 | 68.9 | 95.5 | + | ByteTrack | 73.0 | 72.5 | 96.4 | + | OC-SORT | 71.7 | 71.4 | 95.0 | + | C-BIoU | 73.1 | 72.6 | 96.7 | + | BoT-SORT | 73.8 | 73.4 | 96.9 | + | BoT-SORT + ReID | 75.5 | 75.2 | **97.0** | + | McByte | **76.5** | **76.9** | **97.0** | === "Tuned" Results after grid search over tracker parameters. - | Tracker | HOTA | IDF1 | MOTA | - | :-------: | :------: | :------: | :------: | - | SORT | 72.9 | 73.0 | 95.8 | - | ByteTrack | 73.3 | 73.5 | 95.9 | - | OC-SORT | 74.0 | **75.4** | 95.6 | - | BoT-SORT | **74.1** | 74.0 | **96.9** | - | C-BIoU | 73.1 | 72.6 | 96.7 | + | Tracker | HOTA | IDF1 | MOTA | + | :-------------: | :------: | :------: | :------: | + | SORT | 72.9 | 73.0 | 95.8 | + | ByteTrack | 73.3 | 73.5 | 95.9 | + | OC-SORT | 74.0 | 75.4 | 95.6 | + | C-BIoU | 73.1 | 72.6 | 96.7 | + | BoT-SORT | 74.1 | 74.0 | **96.9** | + | BoT-SORT + ReID | **77.8** | **78.5** | **96.9** | + + - Tuned configuration for each tracker. + Tuned configuration for each tracker. The ReID row uses `osnet_x1_0_sportsmot`, an OSNet x1.0 fine-tuned on SportsMOT train (see [encoders](../guides/reid.md#choosing-an-encoder)). ```yaml SORT: @@ -203,6 +230,12 @@ Sports broadcast tracking with fast motion, camera pans, and similar-looking tar track_activation_threshold: 0.7 buffer_ratio_first: 0.3 buffer_ratio_second: 0.5 + + BoT-SORT + ReID: + reid_model: osnet_x1_0_sportsmot + reid_config.fusion: botsort + reid_config.appearance_threshold: 0.3425 + reid_config.proximity_threshold: 0.9953 ``` ## [SoccerNet-tracking](https://arxiv.org/abs/2204.06918) @@ -216,43 +249,52 @@ Long sequences with dense interactions and partial occlusions. Tests long-term I !!! info - Parameters were tuned on the train set. Results are reported on the test set. SoccerNet-tracking has no validation split. This dataset provides oracle (ground-truth) detections. The BoT-SORT row is CMC without appearance; see the [ReID guide](../guides/reid.md) for appearance association. + Parameters were tuned on the train set. Results are reported on the test set. SoccerNet-tracking has no validation split. This dataset provides oracle (ground-truth) detections. The BoT-SORT row is geometry and CMC only; BoT-SORT + ReID adds the encoder named under the table. The [ReID guide](../guides/reid.md#results) carries both fusion methods and the generic and fine-tuned encoders side by side. === "Default" - Results using default tracker parameters. + Results using default tracker parameters. The ReID row is BoT-SORT at library defaults with the default `fastreid_mot17_sbs50` encoder, BoT-SORT's own ReID model trained on MOT17 pedestrian crops (see [encoders](../guides/reid.md#choosing-an-encoder)). - | Tracker | HOTA | IDF1 | MOTA | - | :-------: | :------: | :------: | :------: | - | SORT | 81.6 | 76.2 | 95.1 | - | ByteTrack | 84.0 | 78.1 | **97.8** | - | OC-SORT | 78.4 | 72.6 | 94.1 | - | BoT-SORT | 84.5 | 79.3 | 96.6 | - | C-BIoU | 82.6 | 76.6 | 97.0 | - | McByte | **85.0** | **79.9** | 97.0 | + | Tracker | HOTA | IDF1 | MOTA | + | :-------------: | :------: | :------: | :------: | + | SORT | 81.6 | 76.2 | 95.1 | + | ByteTrack | 84.0 | 78.1 | **97.8** | + | OC-SORT | 78.4 | 72.6 | 94.1 | + | C-BIoU | 82.6 | 76.6 | 97.0 | + | BoT-SORT | 84.5 | 79.3 | 96.6 | + | BoT-SORT + ReID | 84.3 | 79.1 | 96.5 | + | McByte | **85.0** | **79.9** | 97.0 | === "Tuned" Results after grid search over tracker parameters. - | Tracker | HOTA | IDF1 | MOTA | - | :-------: | :------: | :------: | :------: | - | SORT | 84.2 | 78.2 | 98.2 | - | ByteTrack | 84.0 | 78.1 | 98.2 | - | OC-SORT | 82.9 | 77.9 | 96.8 | - | BoT-SORT | 85.0 | 79.7 | 97.2 | - | C-BIoU | **85.7** | **80.0** | **99.3** | + | Tracker | HOTA | IDF1 | MOTA | + | :-------------: | :------: | :------: | :------: | + | SORT | 84.2 | 78.2 | 98.2 | + | ByteTrack | 84.0 | 78.1 | 98.2 | + | OC-SORT | 82.9 | 77.9 | 96.8 | + | C-BIoU | 85.7 | 80.0 | **99.3** | + | BoT-SORT | 85.0 | 79.7 | 97.2 | + | BoT-SORT + ReID | **88.4** | **84.4** | **99.3** | + + - Tuned configuration for each tracker. + Tuned configuration for each tracker. The ReID row uses `osnet_x1_0_soccernet`, an OSNet x1.0 fine-tuned on SoccerNet train (see [encoders](../guides/reid.md#choosing-an-encoder)). ```yaml SORT: @@ -297,6 +339,14 @@ Long sequences with dense interactions and partial occlusions. Tests long-term I track_activation_threshold: 0.48 buffer_ratio_first: 0.68 buffer_ratio_second: 0.50 + + BoT-SORT + ReID: + reid_model: osnet_x1_0_soccernet + reid_config.fusion: adaptive + reid_config.appearance_weight: 0.75 + reid_config.adaptive_weight_cap: 0.5 + reid_config.proximity_threshold: 1.0 + reid_config.appearance_floor: 0.8 ``` !!! note "SoccerNet buffer ordering exception" @@ -318,38 +368,47 @@ Group dancing tracking with uniform appearance, diverse motions, and extreme art === "Default" - Results using default tracker parameters. + Results using default tracker parameters. The ReID row is BoT-SORT at library defaults with the default `fastreid_mot17_sbs50` encoder, BoT-SORT's own ReID model trained on MOT17 pedestrian crops (see [encoders](../guides/reid.md#choosing-an-encoder)). - | Tracker | HOTA | IDF1 | MOTA | - | :-------: | :------: | :------: | :------: | - | SORT | 47.2 | 41.0 | 86.5 | - | ByteTrack | 53.3 | 53.6 | 90.3 | - | OC-SORT | 54.1 | 53.3 | 89.3 | - | BoT-SORT | 57.8 | 57.9 | 92.2 | - | C-BIoU | 56.7 | 56.7 | 92.2 | - | McByte | **67.2** | **68.6** | **92.5** | + | Tracker | HOTA | IDF1 | MOTA | + | :-------------: | :------: | :------: | :------: | + | SORT | 47.2 | 41.0 | 86.5 | + | ByteTrack | 53.3 | 53.6 | 90.3 | + | OC-SORT | 54.1 | 53.3 | 89.3 | + | C-BIoU | 56.7 | 56.7 | 92.2 | + | BoT-SORT | 57.8 | 57.9 | 92.2 | + | BoT-SORT + ReID | 57.0 | 57.1 | 92.1 | + | McByte | **67.2** | **68.6** | **92.5** | === "Tuned" Hyperparameter tuning, reporting the best tuned configuration per tracker evaluated on the test set (tuning performed on the valid split; if tuning did not outperform registry defaults, defaults are shown). - | Tracker | HOTA | IDF1 | MOTA | - | :-------: | :------: | :------: | :------: | - | SORT | 54.3 | 53.4 | 89.5 | - | ByteTrack | 55.3 | 55.2 | 89.9 | - | OC-SORT | 54.1 | 53.3 | 89.3 | - | BoT-SORT | **57.8** | 57.9 | 92.2 | - | C-BIoU | 57.7 | **58.7** | **92.4** | + | Tracker | HOTA | IDF1 | MOTA | + | :-------------: | :------: | :------: | :------: | + | SORT | 54.3 | 53.4 | 89.5 | + | ByteTrack | 55.3 | 55.2 | 89.9 | + | OC-SORT | 54.1 | 53.3 | 89.3 | + | C-BIoU | 57.7 | 58.7 | **92.4** | + | BoT-SORT | 57.8 | 57.9 | 92.2 | + | BoT-SORT + ReID | **60.8** | **61.6** | 91.7 | + + - Best configuration for each tracker. + Best configuration for each tracker. The ReID row uses `osnet_x1_0_dancetrack`, an OSNet x1.0 fine-tuned on DanceTrack train (see [encoders](../guides/reid.md#choosing-an-encoder)). ```yaml SORT: @@ -394,6 +453,12 @@ Group dancing tracking with uniform appearance, diverse motions, and extreme art high_conf_det_threshold: 0.34 buffer_ratio_first: 0.12 buffer_ratio_second: 0.10 + + BoT-SORT + ReID: + reid_model: osnet_x1_0_dancetrack + reid_config.fusion: botsort + reid_config.appearance_threshold: 0.4716 + reid_config.proximity_threshold: 0.6802 ``` !!! note "DanceTrack buffer ordering exception" @@ -412,7 +477,9 @@ Group dancing tracking with uniform appearance, diverse motions, and extreme art **BoT-SORT** is the choice when camera ego-motion is strong and you need the most stable identities. It extends ByteTrack with camera motion compensation (CMC) and confidence-aware association, which reduces ID switches on panning or handheld footage. Use BoT-SORT for sports broadcasts, drone video, or any scene where the camera moves frequently. The CMC overhead is small relative to the detector, so the trade-off favors identity stability over raw speed. -**C-BIoU** targets fast or irregular motion when you want buffered, cascaded geometric matching without camera motion compensation. In these benchmarks it leads on SoccerNet when tuned, and reaches the highest tuned IDF1 and MOTA on DanceTrack among the motion-only trackers. Use C-BIoU when BoT-SORT-style association is a good fit but CMC is unavailable or harmful, or when plain IoU matching is too strict. See [C-BIoU](../trackers/cbiou.md) for buffer scales **b1** and **b2**. +**C-BIoU** targets fast or irregular motion when you want buffered, cascaded geometric matching without camera motion compensation. In these benchmarks it leads on SoccerNet among the motion-only trackers when tuned, and reaches the highest tuned IDF1 and MOTA on DanceTrack among the motion-only trackers. Use C-BIoU when BoT-SORT-style association is a good fit but CMC is unavailable or harmful, or when plain IoU matching is too strict. See [C-BIoU](../trackers/cbiou.md) for buffer scales **b1** and **b2**. + +**BoT-SORT + ReID** adds an appearance encoder to BoT-SORT's association; enable it with `reid_model=`. Appearance helps where overlap alone cannot tell candidates apart. It can only relink a track that is still kept as lost, for `lost_track_buffer` frames (30 by default, about one second), and at the default `reid_config.proximity_threshold` it only scores pairs that already overlap. Recovering a target that leaves the frame takes a fully open gate and a buffer long enough to cover the absence, see [Choosing a proximity threshold](../guides/reid.md#choosing-a-proximity-threshold). The gain depends on how well the encoder separates your targets: largest with an encoder trained on footage like yours, smallest when targets look alike. Tune the ReID thresholds on your data with [`trackers tune`](../guides/tune.md#tune-reid-thresholds). **McByte** is the choice when you want the highest identity stability and can afford optional SAM/Cutie mask dependencies. It extends BoT-SORT-style association with temporally propagated segmentation masks as an extra matching cue, requiring no per-video tuning. Reported against Trackers' BoT-SORT baseline (without re-identification) at default parameters, McByte improves HOTA and IDF1 on all four datasets in this comparison, with the largest gain on DanceTrack. Use McByte when identity consistency matters more than raw throughput or dependency footprint. See [McByte](../trackers/mcbyte.md) for setup and the mask-conditioning parameters. diff --git a/docs/guides/reid.md b/docs/guides/reid.md index 58c37cf02..3a48e2cec 100644 --- a/docs/guides/reid.md +++ b/docs/guides/reid.md @@ -1,5 +1,5 @@ --- -title: ReID Appearance — BoT-SORT Appearance Association | Trackers +title: ReID Appearance description: Use ReID appearance association with BoT-SORT in Roboflow Trackers, from model loading to appearance threshold selection, with MOT17 and SoccerNet results. --- @@ -11,8 +11,8 @@ BoT-SORT can fuse appearance embeddings with IoU during association. Embeddings - How to enable appearance association on BoT-SORT - Which parameters control the appearance gate -- How to pick `ReIDConfig.appearance_threshold` for your encoder and domain -- What ReID changes on MOT17 and SoccerNet +- How to pick `reid_config.appearance_threshold` for your encoder and domain +- What ReID changes on MOT17, SportsMOT, DanceTrack and SoccerNet, with a generic and a fine-tuned encoder --- @@ -22,7 +22,7 @@ BoT-SORT can fuse appearance embeddings with IoU during association. Embeddings pip install "trackers[reid]" ``` -The `reid` extra installs the [`reid`](https://github.com/roboflow/re-ID) package, which loads the encoders and brings PyTorch with it. To combine it with other extras, such as `detection` for running a detector from the CLI, or to install with `uv`, see the [install guide](install.md#reid-bot-sort-appearance). +For extra contents and other options, see the [install guide](install.md). --- @@ -41,7 +41,7 @@ The `reid` extra installs the [`reid`](https://github.com/roboflow/re-ID) packag === "CLI" - `--reid.model` takes a curated alias, an `hf://` URL, or a local path, and enables appearance association on its own. The appearance gate is `--tracker.reid_config.appearance_threshold`. See the [CLI reference](cli.md) for every argument. + `--reid.model` takes a curated alias, an `hf://` URL, or a local path, and enables appearance association on its own. Tracker parameters keep their Python names, so the appearance gate is `--tracker.reid_config.appearance_threshold`. See the [CLI reference](cli.md) for every argument. ```bash trackers track \ @@ -56,30 +56,82 @@ The `reid` extra installs the [`reid`](https://github.com/roboflow/re-ID) packag Pass the current video frame as `tracker.update(detections, frame=frame_bgr)`. When `reid_model` is set, `update()` raises if `frame` is omitted. -For the model catalog and fine-tuning, see the [`reid` training guide](https://github.com/roboflow/re-ID/blob/main/docs/learn/train.md). +Fine-tuning an encoder on your own data is coming to the `reid` package. --- ## Key Parameters -| Parameter | Purpose | Tuning guidance | -| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | -| `reid_model` | Appearance encoder queried during association. | Leave unset for IoU and CMC only. Pick a checkpoint trained on your object domain where possible. | -| `reid_config.ema_alpha` | EMA momentum for a track's appearance feature. | Default 0.9. Higher keeps a stable long-term identity; lower adapts faster to appearance change but drifts more. | -| `reid_config.appearance_threshold` | Maximum appearance distance `d_app` for appearance to lower a pair's matching cost. | BoT-SORT paper default 0.25. Calibrate per encoder and domain, see below. | -| `reid_config.proximity_threshold` | IoU gate applied before appearance (`IoU ≥ 1 - reid_config.proximity_threshold`), from true IoU even with GIoU/DIoU/CIoU. | Default 0.5. Lower restricts how far apart a pair may be before appearance stops contributing. | +| Parameter | Purpose | Tuning guidance | +| :--------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | +| `reid_model` | Appearance encoder queried during association. | Leave unset for IoU and CMC only. Pick a checkpoint trained on your object domain where possible. | +| `reid_config.ema_alpha` | EMA momentum for a track's appearance feature. | Default 0.9. Higher keeps a stable long-term identity; lower adapts faster to appearance change but drifts more. | +| `reid_config.appearance_threshold` | Maximum appearance distance for appearance to lower a pair's matching cost with `"botsort"`. | Default 0.25 (BoT-SORT paper). Calibrate per encoder and domain, see below. | +| `reid_config.proximity_threshold` | IoU gate applied before appearance (`IoU ≥ 1 - reid_config.proximity_threshold`), from true IoU even with GIoU/DIoU/CIoU. | Default 0.5. Raise to 1.0 where targets leave the frame and return, see [below](#choosing-a-proximity-threshold). | +| `reid_config.fusion` | How appearance combines with geometry: `"botsort"` takes the minimum of the two costs, `"adaptive"` adds a weighted appearance term. | Default `"botsort"`. See [choosing a fusion method](#choosing-a-fusion-method) before switching. | +| `reid_config.appearance_weight` | Base appearance weight when `reid_config.fusion="adaptive"`. Ignored otherwise. | Default 0.75. Raise where geometry is unreliable, see below. | +| `reid_config.adaptive_weight_cap` | Ceiling on the adaptive bonus when `reid_config.fusion="adaptive"`. Ignored otherwise. | Default 0.5. Raise together with `reid_config.appearance_weight`. | +| `reid_config.appearance_floor` | Minimum cosine similarity for appearance to contribute with `"adaptive"`; below it a pair is scored on geometry alone. | Default 0.0 (off, as in Deep OC-SORT). Calibrate per encoder; 0.8 is used for the tuned SoccerNet result below. | + +--- + +## Choosing an encoder + +The encoder decides how much appearance can help, and every threshold below depends on it. There are two kinds: + +- **A generic encoder**, used as published. The one used here is `fastreid_mot17_sbs50`, a FastReID SBS model with a ResNeSt-50 backbone and 25.4M parameters, trained on MOT17 pedestrian crops and released with [BoT-SORT](https://github.com/NirAharon/BoT-SORT). `trackers track` and `trackers tune` load it when ReID is enabled without naming a model; in Python, load it with `ReIDModel.from_pretrained("fastreid_mot17_sbs50")`, as in the [quickstart](#quickstart). It works out of the box, and how much it helps depends on the dataset, see [results](#results). +- **An encoder fine-tuned on your footage**, where the largest gains in the results come from. The results use an [OSNet](https://arxiv.org/abs/1905.00953) x1.0, a much smaller network with 2.2M parameters, fine-tuned on each dataset's train split. All four are available by name: `osnet_x1_0_mot17`, `osnet_x1_0_sportsmot`, `osnet_x1_0_dancetrack` and `osnet_x1_0_soccernet`. Load one with `ReIDModel.from_pretrained("osnet_x1_0_sportsmot")`, or pass the name to `--reid.model` on the command line. Training your own is coming to the `reid` package. + +Each encoder has its own distance scale, so choose the thresholds for the encoder you will track with. + +--- + +## Choosing a fusion method + +On every frame, BoT-SORT gives each track and detection pair a score and then picks the best matching. With ReID enabled, that score combines two signals: how much the boxes overlap, and how alike the two crops look. `reid_config.fusion` sets how they are combined: + +```python +tracker = BoTSORTTracker( + reid_model=reid_model, + reid_config=ReIDConfig(fusion="adaptive"), # default: "botsort" +) +``` + +- `"botsort"`: a pair scores as well as the stronger of the two, `score = 1 - min(box distance, appearance distance)`. +- `"adaptive"`: the two add up, `score = box overlap + weight * appearance similarity`. + +In more detail: + +**`"botsort"`.** Appearance is only used for a pair when its distance is below `reid_config.appearance_threshold` and the boxes pass the `reid_config.proximity_threshold` check. Otherwise the pair is scored on box overlap alone. + +**`"adaptive"`.** This is the appearance fusion from Deep OC-SORT. Each pair starts from its box overlap, and appearance is added on top: `score = box overlap + (reid_config.appearance_weight + bonus) * appearance similarity`. The bonus rewards a clear winner. For a track, it is how much more its most similar detection looks like it than the second most similar one; for a detection, the same against its two most similar tracks. Each margin is capped at `reid_config.adaptive_weight_cap`, and the pair's bonus is their average. So appearance counts more when one candidate clearly stands out, and less when several look alike. Negative similarities count as zero, so appearance can only raise a score. `reid_config.appearance_floor`, added by this library, sets the lowest appearance similarity that counts: below it, a pair is scored on box overlap alone. With the proximity gate open, this stops a lost track from taking an unrelated detection that only looks vaguely similar. + +!!! note "What `adaptive` includes" + + Only the appearance fusion is taken from Deep OC-SORT; the rest of that tracker is not added to BoT-SORT. `reid_config.appearance_threshold` has no effect with `reid_config.fusion="adaptive"`. + +Two consequences are worth knowing before switching: + +- **The similarity range changes.** `"botsort"` returns values in `[0, 1]`; `"adaptive"` returns `[0, 1 + reid_config.appearance_weight + reid_config.adaptive_weight_cap]`, which is `[0, 2.25]` at the defaults. Two thresholds are applied to that fused value: `minimum_iou_threshold_first_assoc`, which matches detections to confirmed and lost tracks, and `minimum_iou_threshold_unconfirmed_assoc`, which matches what is left to tracks that are not confirmed yet. Both are a different gate under the other method, so retune them when you switch, or the comparison measures the gate rather than the fusion. `minimum_iou_threshold_second_assoc` is unaffected, because that step matches on IoU alone. +- **The weights are domain-dependent.** The Deep OC-SORT paper uses `reid_config.appearance_weight=0.75` with `reid_config.adaptive_weight_cap=0.5` for MOT17, and `1.25` with `1.0` for DanceTrack, where dancers occlude constantly and geometry carries less. The defaults here follow the MOT17 pair. + +With the gate open, `adaptive` keeps IDs more stable than `"botsort"`, which switches between look-alike candidates from one frame to the next. `"botsort"` stays the default because it is the safer choice: appearance is only used below `reid_config.appearance_threshold`, and turning it on does not require retuning the other thresholds. --- ## Choosing an appearance threshold -BoT-SORT fuses costs as `min(d_iou, d_app)` with `d_app = 0.5 * (1 - cos_sim)`, and discards the appearance term when `d_app` exceeds `reid_config.appearance_threshold` (paper default 0.25) or when the pair fails the `reid_config.proximity_threshold` IoU gate. Appearance can therefore only lower a pair's cost, never veto a geometric match. Pick $\theta$ on a labeled split with the encoder you will track with: +This threshold only applies to `reid_config.fusion="botsort"`; with `"adaptive"` it has no effect. + +`reid_config.appearance_threshold` is how different two crops may look and still count as the same target. Appearance is compared as a distance, `0.5 * (1 - cosine similarity)`, running from 0 for identical crops to 1 for opposite ones; the BoT-SORT paper uses 0.25. Below the threshold, looking alike makes the tracker more willing to pair the two; above it, the pair stands on box overlap alone. Appearance only ever lowers a pair's cost, never raises it, but the assignment weighs every pair at once, so a look-alike pair can still take a detection away from a track that merely overlapped it. + +The right value depends on the encoder and the footage, so measure it on labeled data: -1. Embed GT crops. -2. Histogram `d_app` for association-local pairs: same video only, with frame gap bounded by the lost-track horizon (default 30 frames). Positives are same-ID; negatives are different-ID that could co-compete. Sample both classes with the same per-sequence quota, otherwise one crowded sequence decides the answer. -3. Choose $\theta$ so most same-ID pairs fall below it and most different-ID pairs fall above it. +1. Embed the ground-truth crops with the encoder you will track with. +2. Compare pairs of crops that could meet during tracking: same video, at most the lost-track buffer apart (30 frames by default). Take the same number of pairs from each sequence, so one crowded video does not decide the result. +3. Pick the value that keeps most same-person pairs below it and lets few different-person pairs through. -All three steps ship with Trackers, so you can run them on your own footage. `extract_ground_truth_embeddings` reads any MOT-format dataset, meaning a `gt/gt.txt` and an `img1` folder per sequence, and returns each crop's embedding alongside the identity, frame and sequence it came from: +Trackers has a helper for each step. `extract_ground_truth_embeddings` reads any dataset in [MOT format](../evaluations/evaluate.md#data-format): ```python from trackers.core.reid import ( @@ -97,21 +149,30 @@ for threshold in (0.10, 0.20, 0.25): plot_appearance_distances(distances, thresholds={0.20: "selected", 0.25: "default"}) ``` -See the [ReID API reference](../api/reid.md#choosing-a-threshold) for the full signatures. The figures on this page were produced with these helpers on MOT17 val and SoccerNet test ground truth. To reproduce them end to end, from download to calibrated threshold, open the [ReID cookbook](https://colab.research.google.com/github/roboflow/trackers/blob/develop/docs/cookbooks/how-to-add-reid-to-trackers.ipynb) in Colab. +The [ReID API reference](../api/reid.md#choosing-a-threshold) lists the full signatures, and the [ReID cookbook](https://colab.research.google.com/github/roboflow/trackers/blob/develop/docs/cookbooks/how-to-add-reid-to-trackers.ipynb) runs the whole flow in Colab. The example below uses 5000 same-person and 10000 different-person pairs, 1 to 30 frames apart. -**MOT17 val, `fastreid_mot17_sbs50`.** Same-ID distances peak near 0 and different-ID near 0.4. On association-local GT crop pairs (5000 same-ID, 10000 different-ID, frame gap 1 to 30), $\theta = 0.2$ keeps 68% of same-ID pairs while passing 1.1% of different-ID pairs. Raising $\theta$ to the BoT-SORT default 0.25 recovers same-ID pairs (79%) but nearly triples the different-ID pairs it admits (2.9%), which is why 0.2 is the better operating point here ([MOT17 re-ID study](https://www-sop.inria.fr/members/Francois.Bremond/Postscript/Tomasz__SCCAI_2025.pdf) Table 8 uses the same threshold). +### MOT17 with an encoder trained on MOT17 + +Blue bars are pairs of the same person, red bars are pairs of different people. A good threshold sits where the blue bars end and the red ones start. `fastreid_mot17_sbs50` on MOT17 val keeps the two groups mostly apart, with some overlap between 0.2 and 0.35.  -**SoccerNet test, `osnet_x1_0_msmt17_combineall`.** A pedestrian encoder on soccer footage squeezes every distance into a narrow range: same-ID pairs peak near 0.05 and different-ID pairs near 0.20 (similar kits). The two shapes still separate, but the scale no longer matches the thresholds BoT-SORT was tuned with. On association-local GT crop pairs (5000 same-ID, 10000 different-ID, frame gap 1 to 30), $\theta = 0.2$ admits 96% of same-ID pairs but also 49% of different-ID pairs, and tracking stays flat against CMC-only. $\theta = 0.1$ holds different-ID pairs to 9%, yet appearance still assists a mix of correct and same-kit pairs and costs HOTA and IDF1 (see the SoccerNet table below). Calibrate $\theta$ on your own domain rather than carrying 0.2 or 0.25 across. +This is what `rates_at` prints for two thresholds: + +| `reid_config.appearance_threshold` | same-person pairs below | different-person pairs below | +| :--------------------------------- | :---------------------: | :--------------------------: | +| 0.20 | 68% | 1.1% | +| 0.25 (paper default) | 79% | 2.9% | + +Moving the threshold right accepts more same-person pairs, but it also starts letting different-person pairs through. We use 0.2, the same value as the [MOT17 re-ID study](https://www-sop.inria.fr/members/Francois.Bremond/Postscript/Tomasz__SCCAI_2025.pdf) (Table 8). - +If the two groups overlap instead, no threshold separates them: any value that keeps most same-person pairs also lets many different-person pairs through. Check the [proximity threshold](#choosing-a-proximity-threshold) and [fusion method](#choosing-a-fusion-method) first, and consider an encoder fine-tuned on your footage, see [results](#results). --- ## How far the threshold carries -To choose `lost_track_buffer`, it helps to see how Re-ID behaves as the frame gap grows. A player's encoded appearance can change over time, so `sweep_frame_gap` samples labeled crop pairs across widening gap bands. It does not simulate dropped frames or occlusions. Plot the results with `plot_frame_gap_sweep`: +A histogram fixes one frame gap, so it only describes re-association over that horizon. Sweeping the gap shows how long a track can stay lost before appearance stops helping to re-find it. `sweep_frame_gap` repeats the sampling above across widening bands, and `plot_frame_gap_sweep` draws the result: ```python from trackers.core.reid import plot_frame_gap_sweep, sweep_frame_gap @@ -120,24 +181,237 @@ sweep = sweep_frame_gap(embeddings, ids, frame_ids, sequence_ids) plot_frame_gap_sweep(sweep, thresholds={0.20: "selected", 0.25: "default"}) ``` -On MOT17 val, the typical appearance difference between two different people stays near 0.41 even at gaps up to 240 frames. For the same person, it grows from 0.04 one frame apart to 0.20 at 16 to 30 frames and 0.28 at 121 to 240 frames. Smaller values mean the crops look more alike, so matching the same person gets harder as the gap grows. +On MOT17 val, pairs of different people stay about as far apart at every gap. Pairs of the same person drift apart as the gap grows, because pose, lighting and occlusion change, so a threshold that catches them one frame apart misses more of them after a long absence. -ROC AUC shows how well the encoder separates same-ID from different-ID pairs across all thresholds: 1.0 is perfect separation, while 0.5 is no better than chance. The shaded bands in the plot show where most pair scores fall; AUC uses every pair. The last two columns show the share of each group accepted at the 0.2 threshold. + -| Frame gap | ROC AUC | same-ID below 0.2 | different-ID below 0.2 | -| :--------- | :-----: | :---------------: | :--------------------: | -| 1 | 0.998 | 98.0% | 1.7% | -| 2 to 5 | 0.987 | 87.6% | 1.6% | -| 6 to 15 | 0.957 | 67.4% | 1.1% | -| 16 to 30 | 0.929 | 51.4% | 1.1% | -| 31 to 60 | 0.899 | 39.8% | 0.9% | -| 61 to 120 | 0.865 | 31.8% | 0.8% | -| 121 to 240 | 0.854 | 28.7% | 0.8% | +From this we learn: - +- **Check the threshold at the gap you care about.** A threshold that works one frame apart can fail after a lost track: at 0.2 it matches 98% of same-person pairs one frame apart, but only 51% across the default 30-frame `lost_track_buffer`. +- **Long gaps make people harder to tell apart.** The same person looks less like themselves after a long absence, so same-person and different-person distances overlap more: ROC AUC, explained below, falls from 0.998 at a 1-frame gap to 0.854 beyond 120 frames. With the threshold at 0.2, appearance stops recognizing most people after a long absence: only 29% of same-person pairs more than 120 frames apart are under 0.2, against 98% one frame apart. Raising the threshold to catch those also lets more different people through, so if you increase `lost_track_buffer`, check both rates at that gap before raising `reid_config.appearance_threshold`. + +??? info "How to read ROC AUC, and the numbers per frame gap" + + ROC AUC answers one question: if you pick one pair of crops of the same person and one pair of different people at random, how often is the same-person pair closer? 1.0 means always, so some threshold separates the two groups perfectly. 0.5 means a coin flip, so appearance tells you nothing. Unlike the two rates in the table, it does not depend on a chosen threshold. It is also not where the shaded bands overlap in the figure: those bands only span the 10th to 90th percentiles, so at a 1-frame gap they never touch even though the AUC is 0.998. + + How it is calculated: each frame-gap band gets its own sample of same-person and different-person pairs. For every threshold from 0 to 1, count the share of same-person pairs below it and the share of different-person pairs below it, and plot the first share against the second. That traces the ROC curve from (0, 0) to (1, 1), and ROC AUC is the area under it. `sweep_frame_gap` gets the same number without drawing the curve, by comparing every same-person distance with every different-person distance and counting how often the same-person one is smaller, with ties counting as half (`trackers.core.reid.roc_auc`). The result is the lower panel of the figure above. + + The last two columns show the two rates at a threshold of 0.2. + + | Frame gap | ROC AUC | same-ID below 0.2 | different-ID below 0.2 | + | :--------- | :-----: | :---------------: | :--------------------: | + | 1 | 0.998 | 98.0% | 1.7% | + | 2 to 5 | 0.987 | 87.6% | 1.6% | + | 6 to 15 | 0.957 | 67.4% | 1.1% | + | 16 to 30 | 0.929 | 51.4% | 1.1% | + | 31 to 60 | 0.899 | 39.8% | 0.9% | + | 61 to 120 | 0.865 | 31.8% | 0.8% | + | 121 to 240 | 0.854 | 28.7% | 0.8% | + +--- -Two things follow. First, a threshold validated on adjacent frames says little about re-association: at $\theta = 0.2$ appearance helps 98% of same-ID pairs one frame apart but only 51% across the default 30-frame lost-track buffer. Second, the price of a tight $\theta$ over long gaps is missed re-associations rather than extra wrong ones, because the different-ID rate stays near 1% throughout. If you raise `lost_track_buffer` to recover tracks after long occlusions, raise `reid_config.appearance_threshold` with it and re-check the different-ID column. +## Choosing a proximity threshold -The cross-domain encoder fails differently. On SoccerNet the different-ID rate at $\theta = 0.2$ stays between 44% and 51% at every gap, so the frame gap is not what limits it; the encoder simply cannot separate players in matching kits at any horizon. Widening the gap costs same-ID pairs (99.6% down to 87.0%) without ever making the different-ID side usable, which is why $\theta$ has to come down to about 0.1 on this domain instead of being traded against the gap. +`reid_config.proximity_threshold` decides which track-detection pairs appearance is allowed to score. A pair is dropped before appearance is consulted whenever `1 - IoU` exceeds the threshold, so the 0.5 default limits appearance to pairs that already overlap at `IoU >= 0.5`, and 0.99 still requires `IoU >= 0.01`. Only 1.0 disables the gate. + +While a track is lost it has no detection of its own, so it is matched through its estimated position, which keeps moving as if the target had carried on. After a short occlusion that estimate has drifted, so it barely overlaps the detection when the target reappears. After the target leaves the frame it drifts out of view entirely and the overlap drops to zero. The 0.5 default blocks appearance in both cases, 0.99 lets it score the first one, and only 1.0 lets it score the second. BoT-SORT has no separate step for targets that leave and return, so opening the gate is the only way to keep their ID. + +SoccerNet test, oracle detections, `osnet_x1_0_soccernet`, library-default motion parameters, `reid_config.fusion="adaptive"` with its default weights: + +| `reid_config.proximity_threshold` | appearance consulted when | HOTA | IDF1 | ID switches | +| :-------------------------------- | :------------------------ | :---: | :---: | :---------: | +| none (no ReID) | | 84.56 | 79.35 | 2939 | +| 0.5 (default) | `IoU >= 0.50` | 84.52 | 79.27 | 3012 | +| 0.8 | `IoU >= 0.20` | 85.02 | 79.71 | 3268 | +| 1.0 | always | 85.46 | 81.18 | 1734 | + + +
SoccerNet SNMOT-147, top to bottom: gate 0.5, 0.8 and 1.0. The player who leaves the frame gets a new ID at 0.5 and 0.8, and keeps it at 1.0.
+ +HOTA and IDF1 improve as the gate opens, but ID switches do not follow the same curve. At 0.8 they are higher than with the default gate or without ReID: appearance can now match more distant boxes, but not yet the ones that recover a lost track. With the gate fully open they drop below both. If you open the gate, open it all the way. + +The right value depends on the footage. Use 1.0 when targets leave the frame or the camera moves a lot. Keep 0.5 when targets stay in view, as in DanceTrack: there an open gate only adds wrong matches between people who look alike. + +--- + +## Tuning the thresholds + +The steps above give a good starting point. `trackers tune` then searches `reid_config.appearance_threshold` and `reid_config.proximity_threshold` together, keeping the motion parameters you pass fixed, see [Tune ReID Thresholds](tune.md#tune-reid-thresholds). The command tunes the `"botsort"` thresholds; for `"adaptive"` it does not search the weights yet. + +--- - +## Results + +BoT-SORT with and without ReID on the test splits, using the same detections and motion parameters. The ReID thresholds were tuned on a separate split first, and each configuration was then evaluated once on test. The best value for each dataset is in bold. Motion parameters are the tuned values from the [tracker comparison](../evaluations/results.md). + + + +=== "Fine-tuned encoder" + + `osnet_x1_0` fine-tuned on each dataset's train split (`osnet_x1_0_mot17`, `osnet_x1_0_sportsmot`, `osnet_x1_0_dancetrack`, `osnet_x1_0_soccernet`), with `reid_config.fusion="botsort"` and `reid_config.fusion="adaptive"`. + + | Dataset | Config | HOTA | IDF1 | MOTA | + | :--------: | :-------------------------- | :------: | :------: | :------: | + | MOT17 | BoT-SORT | 63.8 | 78.7 | **79.4** | + | | BoT-SORT + ReID | **64.0** | 78.9 | **79.4** | + | | BoT-SORT + ReID, `adaptive` | **64.0** | **79.2** | **79.4** | + | SportsMOT | BoT-SORT | 74.1 | 74.1 | 96.9 | + | | BoT-SORT + ReID | **77.8** | **78.5** | 96.9 | + | | BoT-SORT + ReID, `adaptive` | 76.4 | 76.8 | **97.0** | + | DanceTrack | BoT-SORT | 57.8 | 57.9 | 92.2 | + | | BoT-SORT + ReID | **60.8** | **61.6** | 91.7 | + | | BoT-SORT + ReID, `adaptive` | 58.3 | 58.2 | **92.3** | + | SoccerNet | BoT-SORT | 85.0 | 79.7 | 97.2 | + | | BoT-SORT + ReID | 87.3 | 83.2 | 98.7 | + | | BoT-SORT + ReID, `adaptive` | **88.4** | **84.4** | **99.3** | + + ??? info "Tuned ReID configuration" + + Tuned ReID configuration for each dataset and fusion method. Motion parameters are the BoT-SORT values from the [tracker comparison](../evaluations/results.md), except `minimum_iou_threshold_first_assoc` where listed. + + ```yaml + MOT17: + botsort: + reid_model: osnet_x1_0_mot17 + reid_config.appearance_threshold: 0.0448 + reid_config.proximity_threshold: 0.2697 + adaptive: + reid_model: osnet_x1_0_mot17 + reid_config.appearance_weight: 2.124 + reid_config.adaptive_weight_cap: 0.959 + reid_config.appearance_floor: 0.569 + reid_config.proximity_threshold: 0.342 + minimum_iou_threshold_first_assoc: 0.205 + + SportsMOT: + botsort: + reid_model: osnet_x1_0_sportsmot + reid_config.appearance_threshold: 0.3425 + reid_config.proximity_threshold: 0.9953 + adaptive: + reid_model: osnet_x1_0_sportsmot + reid_config.appearance_weight: 1.290 + reid_config.adaptive_weight_cap: 0.718 + reid_config.appearance_floor: 0.510 + reid_config.proximity_threshold: 0.983 + minimum_iou_threshold_first_assoc: 0.329 + + DanceTrack: + botsort: + reid_model: osnet_x1_0_dancetrack + reid_config.appearance_threshold: 0.4716 + reid_config.proximity_threshold: 0.6802 + adaptive: + reid_model: osnet_x1_0_dancetrack + reid_config.appearance_weight: 1.947 + reid_config.adaptive_weight_cap: 0.944 + reid_config.appearance_floor: 0.614 + reid_config.proximity_threshold: 0.690 + minimum_iou_threshold_first_assoc: 0.946 + + SoccerNet: + botsort: + reid_model: osnet_x1_0_soccernet + reid_config.appearance_threshold: 0.075 + reid_config.proximity_threshold: 1.0 + adaptive: + reid_model: osnet_x1_0_soccernet + reid_config.appearance_weight: 0.75 + reid_config.adaptive_weight_cap: 0.5 + reid_config.proximity_threshold: 1.0 + reid_config.appearance_floor: 0.8 + ``` + + Every configuration was tuned with `trackers tune` on its own tuning split¹, 20 trials per fusion method, then evaluated once on test. + + ¹ SoccerNet-tracking has no validation split. This encoder was trained on the first 45 of the 57 train sequences, so its thresholds were tuned on the other 12 (SNMOT-159 to SNMOT-170). The other datasets tune on val, MOT17 on val-half. + + Fine-tuning improves on BoT-SORT without ReID on every dataset: on test it adds 3.67 HOTA on SportsMOT, 3.43 on SoccerNet with `adaptive`, 3.00 on DanceTrack and 0.20 on MOT17. + + Each encoder is one training run, and training is not deterministic across seeds: two SportsMOT encoders trained identically apart from the seed scored 83.50 and 83.72 on val, and on DanceTrack the spread across three seeds reached 1.54 HOTA. Treat differences below a point between fine-tuned rows as noise. The SportsMOT encoder is the better of its two seeds, chosen on val; `crops_per_identity=8` is carried over from DanceTrack rather than tuned per dataset. + +=== "Generic encoder" + + Encoders used as published, without training on your data. `fastreid_mot17_sbs50` was trained on MOT17 by the BoT-SORT authors, so its MOT17 rows are in domain; on the other datasets it has not seen the footage, and it still helps on SportsMOT. Both fusion methods were tuned with `trackers tune`, 20 trials each, on each dataset's tuning split². + + | Dataset | Config | HOTA | IDF1 | MOTA | + | :--------: | :-------------------------- | :------: | :------: | :------: | + | MOT17 | BoT-SORT | 63.8 | 78.7 | **79.4** | + | | BoT-SORT + ReID | 63.8 | 78.8 | **79.4** | + | | BoT-SORT + ReID, `adaptive` | **64.6** | **79.9** | **79.4** | + | SportsMOT | BoT-SORT | 74.1 | 74.1 | **96.9** | + | | BoT-SORT + ReID | **75.5** | **75.5** | **96.9** | + | | BoT-SORT + ReID, `adaptive` | 74.1 | 73.7 | **96.9** | + | DanceTrack | BoT-SORT | **57.8** | **57.9** | 92.2 | + | | BoT-SORT + ReID | 57.6 | 57.6 | 92.1 | + | | BoT-SORT + ReID, `adaptive` | 57.5 | 57.3 | **92.3** | + | SoccerNet | BoT-SORT | 85.0 | 79.7 | 97.2 | + | | BoT-SORT + ReID | 85.0 | 79.7 | 97.2 | + | | BoT-SORT + ReID, `adaptive` | **85.9** | **80.4** | **97.9** | + + ??? info "Tuned ReID configuration" + + Tuned ReID configuration for each dataset. Motion parameters are the BoT-SORT values from the [tracker comparison](../evaluations/results.md). + + ```yaml + MOT17: + botsort: + reid_model: fastreid_mot17_sbs50 + reid_config.appearance_threshold: 0.10 + reid_config.proximity_threshold: 0.5 + adaptive: + reid_model: fastreid_mot17_sbs50 + reid_config.appearance_weight: 1.908 + reid_config.adaptive_weight_cap: 0.545 + reid_config.appearance_floor: 0.381 + reid_config.proximity_threshold: 0.772 + minimum_iou_threshold_first_assoc: 0.846 + + SportsMOT: + botsort: + reid_model: fastreid_mot17_sbs50 + reid_config.appearance_threshold: 0.4761 + reid_config.proximity_threshold: 0.5051 + adaptive: + reid_model: fastreid_mot17_sbs50 + reid_config.appearance_weight: 2.540 + reid_config.adaptive_weight_cap: 0.778 + reid_config.appearance_floor: 0.783 + reid_config.proximity_threshold: 0.216 + minimum_iou_threshold_first_assoc: 0.176 + + DanceTrack: + botsort: + reid_model: fastreid_mot17_sbs50 + reid_config.appearance_threshold: 0.4822 + reid_config.proximity_threshold: 0.5068 + adaptive: + reid_model: fastreid_mot17_sbs50 + reid_config.appearance_weight: 0.75 + reid_config.adaptive_weight_cap: 0.5 + reid_config.appearance_floor: 0.0 + reid_config.proximity_threshold: 0.5 + + SoccerNet: + botsort: + reid_model: fastreid_mot17_sbs50 + reid_config.appearance_threshold: 0.0467 + reid_config.proximity_threshold: 0.3511 + adaptive: + reid_model: fastreid_mot17_sbs50 + reid_config.appearance_weight: 1.178 + reid_config.adaptive_weight_cap: 0.621 + reid_config.appearance_floor: 0.195 + reid_config.proximity_threshold: 0.975 + minimum_iou_threshold_first_assoc: 0.349 + ``` + + ² SoccerNet-tracking has no validation split, so its tuning split is train. The other datasets tune on val, MOT17 on val-half. + + On test, a generic encoder adds HOTA on MOT17 with `adaptive` (+0.72), on SportsMOT with `botsort` (+1.31) and on SoccerNet with `adaptive` (+0.89), and stays below BoT-SORT on DanceTrack. On SoccerNet only the additive rule helps; under `botsort` the same encoder is flat, because the gate it was tuned to keeps appearance away from the pairs that would benefit. + + On MOT17 the tuning split preferred `botsort` by 0.10 HOTA, while `adaptive` scored 0.73 higher on test, the best MOT17 result on this page. + + SoccerNet uses ground-truth boxes as detections, so its numbers are not comparable to the YOLOX rows. diff --git a/docs/index.md b/docs/index.md index 144799c3f..c80f1a8a6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ --- title: Object Tracking in Python comments: false -description: Get started with Roboflow Trackers — install SORT, ByteTrack, OC-SORT, BoT-SORT, C-BIoU, and McByte, run your first tracking pipeline, and evaluate results with HOTA, IDF1, and MOTA metrics. +description: Get started with Roboflow Trackers — install SORT, ByteTrack, OC-SORT, C-BIoU, BoT-SORT, and McByte, run your first tracking pipeline, and evaluate results with HOTA, IDF1, and MOTA metrics. ---