[{"data":1,"prerenderedAt":3609},["ShallowReactive",2],{"navigation":3,"api-navigation":126,"\u002Fmigration":328,"docyard:crossref-index":3608},[4,8,38,44,48,122],{"title":5,"path":6,"stem":7},"Getting Started","\u002Fgetting-started","1.getting-started",{"title":9,"path":10,"stem":11,"children":12,"page":37},"Recipes","\u002Frecipes","2.recipes",[13,17,21,25,29,33],{"title":14,"path":15,"stem":16},"Recipe: two-stage cascade tracker","\u002Frecipes\u002Fcascade_tracker","2.recipes\u002Fcascade_tracker",{"title":18,"path":19,"stem":20},"Recipe: cosine appearance tracker","\u002Frecipes\u002Fcosine_tracker","2.recipes\u002Fcosine_tracker",{"title":22,"path":23,"stem":24},"Recipe: Kalman motion tracker","\u002Frecipes\u002Fkalman_motion_tracker","2.recipes\u002Fkalman_motion_tracker",{"title":26,"path":27,"stem":28},"Recipe: learned MOTR-style appearance tracker","\u002Frecipes\u002Flearned_motr_tracker","2.recipes\u002Flearned_motr_tracker",{"title":30,"path":31,"stem":32},"Recipe: overlap-IoU tracker (port of 1.x models.overlap)","\u002Frecipes\u002Foverlap_tracker","2.recipes\u002Foverlap_tracker",{"title":34,"path":35,"stem":36},"Recipe: SORT-style tracker on unitrack 2.0","\u002Frecipes\u002Fsort","2.recipes\u002Fsort",false,{"title":39,"path":40,"stem":41,"children":42},"API reference","\u002Fapi","3.api\u002Findex",[43],{"title":39,"path":40,"stem":41},{"title":45,"path":46,"stem":47},"Migrating from 1.x to 2.0","\u002Fmigration","4.migration",{"title":49,"path":50,"stem":51,"children":52,"page":37},"Notebooks","\u002Fnotebooks","5.notebooks",[53,84,88],{"title":54,"path":55,"stem":56,"children":57},"Embedding \u002F appearance filters","\u002Fnotebooks\u002Fembedding_filters","5.notebooks\u002Fembedding_filters\u002Findex",[58,59,64,68,72,76,80],{"title":54,"path":55,"stem":56},{"title":60,"path":61,"stem":62,"icon":63},"Embedding filters 1 — Exponential moving average (EMA)","\u002Fnotebooks\u002Fembedding_filters\u002Fema","5.notebooks\u002Fembedding_filters\u002F1.ema","i-lucide-notebook",{"title":65,"path":66,"stem":67,"icon":63},"Embedding filters 2 — Diagonal Kalman","\u002Fnotebooks\u002Fembedding_filters\u002Fkalman_diagonal","5.notebooks\u002Fembedding_filters\u002F2.kalman_diagonal",{"title":69,"path":70,"stem":71,"icon":63},"Embedding filters 3 — von Mises-Fisher (directional)","\u002Fnotebooks\u002Fembedding_filters\u002Fvmf_directional","5.notebooks\u002Fembedding_filters\u002F3.vmf_directional",{"title":73,"path":74,"stem":75,"icon":63},"Embedding filters 4 — Ensemble Kalman & information filters","\u002Fnotebooks\u002Fembedding_filters\u002Fenkf_information","5.notebooks\u002Fembedding_filters\u002F4.enkf_information",{"title":77,"path":78,"stem":79,"icon":63},"Embedding filters 5 — Memory bank & learned propagation","\u002Fnotebooks\u002Fembedding_filters\u002Fgallery_and_learned","5.notebooks\u002Fembedding_filters\u002F5.gallery_and_learned",{"title":81,"path":82,"stem":83,"icon":63},"Embedding filters 6 — summary & benchmark","\u002Fnotebooks\u002Fembedding_filters\u002Fsummary_benchmark","5.notebooks\u002Fembedding_filters\u002F6.summary_benchmark",{"title":85,"path":86,"stem":87,"icon":63},"Kalman filters for motion prediction in tracking","\u002Fnotebooks\u002Fkalman","5.notebooks\u002Fkalman",{"title":89,"path":90,"stem":91,"children":92},"Tutorial notebooks","\u002Fnotebooks\u002Ftutorials","5.notebooks\u002Ftutorials\u002Findex",[93,94,98,102,106,110,114,118],{"title":89,"path":90,"stem":91},{"title":95,"path":96,"stem":97,"icon":63},"1. Quickstart — your first tracker","\u002Fnotebooks\u002Ftutorials\u002Fquickstart","5.notebooks\u002Ftutorials\u002F1.quickstart",{"title":99,"path":100,"stem":101,"icon":63},"2. The data model — typed records that flow through a tracker","\u002Fnotebooks\u002Ftutorials\u002Fdata_model","5.notebooks\u002Ftutorials\u002F2.data_model",{"title":103,"path":104,"stem":105,"icon":63},"3. The cost & gate zoos","\u002Fnotebooks\u002Ftutorials\u002Fcosts_and_gates","5.notebooks\u002Ftutorials\u002F3.costs_and_gates",{"title":107,"path":108,"stem":109,"icon":63},"4. The composable pipeline tree","\u002Fnotebooks\u002Ftutorials\u002Fpipeline_tree","5.notebooks\u002Ftutorials\u002F4.pipeline_tree",{"title":111,"path":112,"stem":113,"icon":63},"5. State evolution and lifecycle","\u002Fnotebooks\u002Ftutorials\u002Fstates_and_lifecycle","5.notebooks\u002Ftutorials\u002F5.states_and_lifecycle",{"title":115,"path":116,"stem":117,"icon":63},"6. End-to-end: K=2 cascaded and parallel fusion","\u002Fnotebooks\u002Ftutorials\u002Fcascaded_and_parallel","5.notebooks\u002Ftutorials\u002F6.cascaded_and_parallel",{"title":119,"path":120,"stem":121,"icon":63},"7. Migration & new possibilities — driven by a real detector","\u002Fnotebooks\u002Ftutorials\u002Fmigration","5.notebooks\u002Ftutorials\u002F7.migration",{"title":123,"path":124,"stem":125},"Unitrack","\u002F","index",[127,130,133,136,139,142,145,148,151,154,157,160,163,166,169,172,175,178,181,184,187,190,193,196,199,202,205,208,211,214,217,220,223,226,229,232,235,238,241,244,247,249,252,255,258,261,263,266,269,272,274,277,280,282,285,288,290,293,296,299,302,305,308,311,313,315,318,320,323,326],{"title":128,"path":129},"assignment","\u002Fapi\u002Fassignment",{"title":131,"path":132},"associate","\u002Fapi\u002Fassignment\u002Fassociate",{"title":134,"path":135},"clip_associate","\u002Fapi\u002Fassignment\u002Fclip_associate",{"title":137,"path":138},"lap","\u002Fapi\u002Fassignment\u002Flap",{"title":140,"path":141},"lapjv","\u002Fapi\u002Fassignment\u002Flapjv",{"title":143,"path":144},"benchmarks","\u002Fapi\u002Fbenchmarks",{"title":146,"path":147},"hota","\u002Fapi\u002Fbenchmarks\u002Fhota",{"title":149,"path":150},"datasets","\u002Fapi\u002Fbenchmarks\u002Fhota\u002Fdatasets",{"title":152,"path":153},"learned_modules","\u002Fapi\u002Fbenchmarks\u002Fhota\u002Flearned_modules",{"title":155,"path":156},"metric","\u002Fapi\u002Fbenchmarks\u002Fhota\u002Fmetric",{"title":158,"path":159},"models","\u002Fapi\u002Fbenchmarks\u002Fhota\u002Fmodels",{"title":161,"path":162},"protocols","\u002Fapi\u002Fbenchmarks\u002Fhota\u002Fprotocols",{"title":164,"path":165},"render","\u002Fapi\u002Fbenchmarks\u002Fhota\u002Frender",{"title":167,"path":168},"report","\u002Fapi\u002Fbenchmarks\u002Fhota\u002Freport",{"title":170,"path":171},"runner","\u002Fapi\u002Fbenchmarks\u002Fhota\u002Frunner",{"title":173,"path":174},"tracker","\u002Fapi\u002Fbenchmarks\u002Fhota\u002Ftracker",{"title":176,"path":177},"train_learned","\u002Fapi\u002Fbenchmarks\u002Fhota\u002Ftrain_learned",{"title":179,"path":180},"types","\u002Fapi\u002Fbenchmarks\u002Fhota\u002Ftypes",{"title":182,"path":183},"costs","\u002Fapi\u002Fcosts",{"title":185,"path":186},"combinators","\u002Fapi\u002Fcosts\u002Fcombinators",{"title":188,"path":189},"distance","\u002Fapi\u002Fcosts\u002Fdistance",{"title":191,"path":192},"gallery","\u002Fapi\u002Fcosts\u002Fgallery",{"title":194,"path":195},"overlap","\u002Fapi\u002Fcosts\u002Foverlap",{"title":197,"path":198},"data","\u002Fapi\u002Fdata",{"title":200,"path":201},"clip","\u002Fapi\u002Fdata\u002Fclip",{"title":203,"path":204},"cost","\u002Fapi\u002Fdata\u002Fcost",{"title":206,"path":207},"detections","\u002Fapi\u002Fdata\u002Fdetections",{"title":209,"path":210},"frame","\u002Fapi\u002Fdata\u002Fframe",{"title":212,"path":213},"gate","\u002Fapi\u002Fdata\u002Fgate",{"title":215,"path":216},"match","\u002Fapi\u002Fdata\u002Fmatch",{"title":218,"path":219},"tensor_spec","\u002Fapi\u002Fdata\u002Ftensor_spec",{"title":221,"path":222},"tracklets","\u002Fapi\u002Fdata\u002Ftracklets",{"title":224,"path":225},"gates","\u002Fapi\u002Fgates",{"title":227,"path":228},"motion","\u002Fapi\u002Fgates\u002Fmotion",{"title":230,"path":231},"simple","\u002Fapi\u002Fgates\u002Fsimple",{"title":233,"path":234},"soft","\u002Fapi\u002Fgates\u002Fsoft",{"title":236,"path":237},"spatial","\u002Fapi\u002Fgates\u002Fspatial",{"title":239,"path":240},"lifecycle","\u002Fapi\u002Flifecycle",{"title":242,"path":243},"filters","\u002Fapi\u002Flifecycle\u002Ffilters",{"title":245,"path":246},"policies","\u002Fapi\u002Flifecycle\u002Fpolicies",{"title":233,"path":248},"\u002Fapi\u002Flifecycle\u002Fsoft",{"title":250,"path":251},"status","\u002Fapi\u002Flifecycle\u002Fstatus",{"title":253,"path":254},"visibility","\u002Fapi\u002Flifecycle\u002Fvisibility",{"title":256,"path":257},"pipeline","\u002Fapi\u002Fpipeline",{"title":259,"path":260},"base","\u002Fapi\u002Fpipeline\u002Fbase",{"title":185,"path":262},"\u002Fapi\u002Fpipeline\u002Fcombinators",{"title":264,"path":265},"diff","\u002Fapi\u002Fpipeline\u002Fdiff",{"title":267,"path":268},"merge","\u002Fapi\u002Fpipeline\u002Fmerge",{"title":270,"path":271},"states","\u002Fapi\u002Fstates",{"title":259,"path":273},"\u002Fapi\u002Fstates\u002Fbase",{"title":275,"path":276},"directional","\u002Fapi\u002Fstates\u002Fdirectional",{"title":278,"path":279},"ema","\u002Fapi\u002Fstates\u002Fema",{"title":191,"path":281},"\u002Fapi\u002Fstates\u002Fgallery",{"title":283,"path":284},"identity","\u002Fapi\u002Fstates\u002Fidentity",{"title":286,"path":287},"kalman","\u002Fapi\u002Fstates\u002Fkalman",{"title":259,"path":289},"\u002Fapi\u002Fstates\u002Fkalman\u002Fbase",{"title":291,"path":292},"bbox","\u002Fapi\u002Fstates\u002Fkalman\u002Fbbox",{"title":294,"path":295},"centroid","\u002Fapi\u002Fstates\u002Fkalman\u002Fcentroid",{"title":297,"path":298},"ensemble","\u002Fapi\u002Fstates\u002Fkalman\u002Fensemble",{"title":300,"path":301},"information","\u002Fapi\u002Fstates\u002Fkalman\u002Finformation",{"title":303,"path":304},"project","\u002Fapi\u002Fstates\u002Fkalman\u002Fproject",{"title":306,"path":307},"update","\u002Fapi\u002Fstates\u002Fkalman\u002Fupdate",{"title":309,"path":310},"learned","\u002Fapi\u002Fstates\u002Flearned",{"title":233,"path":312},"\u002Fapi\u002Fstates\u002Fsoft",{"title":173,"path":314},"\u002Fapi\u002Ftracker",{"title":316,"path":317},"batch","\u002Fapi\u002Ftracker\u002Fbatch",{"title":200,"path":319},"\u002Fapi\u002Ftracker\u002Fclip",{"title":321,"path":322},"memory","\u002Fapi\u002Ftracker\u002Fmemory",{"title":324,"path":325},"multistream","\u002Fapi\u002Ftracker\u002Fmultistream",{"title":173,"path":327},"\u002Fapi\u002Ftracker\u002Ftracker",{"id":329,"title":45,"body":330,"description":3603,"extension":3604,"meta":3605,"navigation":954,"path":46,"seo":3606,"stem":47,"__hash__":3607},"content\u002F4.migration.md",{"type":331,"value":332,"toc":3590},"minimark",[333,337,345,350,358,362,365,635,654,658,839,861,865,875,880,2049,2053,2836,2840,2968,2972,3006,3439,3453,3457,3552,3556,3586],[334,335,45],"h1",{"id":336},"migrating-from-1x-to-20",[338,339,340,344],"p",{},[341,342,343],"code",{},"unitrack"," 2.0 is a hard break. There are no compatibility shims, and a tracker\nwritten against 1.x will not import unchanged: the primitives were re-cut around\na typed data model and a composable stage tree. This page maps the 1.x surface\nonto 2.0 and then migrates a real 1.x tracker — an appearance-embedding matcher\n— end to end.",[346,347,349],"h2",{"id":348},"why-20-is-a-hard-break","Why 2.0 is a hard break",[338,351,352,353,357],{},"Four capabilities the companion paper needs forced the redesign: parallel\nfusion of cost terms, Kalman motion state, first-class gates, and tracklet\nlifecycle. Each is a ",[354,355,356],"em",{},"cross-cutting concern"," — it touches the data model and the\nway stages compose — not a leaf that bolts onto the side. A cross-cutting\nconcern cannot be added to an abstraction that did not anticipate it; you either\nre-cut the abstraction or encode the change as mode flags, and 1.x's untyped\nfield dicts and flat stage list left only the second route. A compatibility\nshim would therefore have frozen the very primitives that had to change. 2.0\nre-cuts the core instead (decisions Q1–Q2). The five shifts below are what a\nmigration touches.",[346,359,361],{"id":360},"what-changed-conceptually","What changed, conceptually",[338,363,364],{},"Five shifts account for almost every edit a migration requires.",[366,367,368,412,448,498,564],"ol",{},[369,370,371,379,380,383,384,387,388,390,391,394,395],"li",{},[372,373,374,375,378],"strong",{},"Field extraction → a typed ",[341,376,377],{},"Detections"," record."," In 1.x,\n",[341,381,382],{},"MultiStageTracker(fields=[...])"," took a list of ",[341,385,386],{},"TensorDictModule","s that\nselected and renamed tensors out of a raw input dict at the front of the\npipeline. 2.0 has no field layer. You construct a ",[341,389,377],{}," tensorclass\nwhose field names match the state schema and pass it to ",[341,392,393],{},"step"," directly.",[396,397,398],"blockquote",{},[338,399,400,403,404,407,408,411],{},[354,401,402],{},"Why:"," the field layer only renamed tensors inside an untyped dict, so a\nschema error surfaced — if at all — deep inside a stage at runtime. A\ntensorclass makes the schema a type: an ill-formed record fails to\nconstruct, and the now-fixed shapes are what let ",[341,405,406],{},"torch.compile"," and ",[341,409,410],{},"vmap","\nspecialize. Checking moves from runtime to construction, and the renaming\nlayer leaves with the dict it served.",[369,413,414,417,418,421,422,425,426,425,429,432,433,436,437],{},[372,415,416],{},"Flat stage list → composable stage tree."," 1.x nested stages as plain\nlists (",[341,419,420],{},"stages=[Gate(then=[Association(...)])]","). 2.0 expresses the same\nstructure as a typed tree of combinators — ",[341,423,424],{},"Pipe",", ",[341,427,428],{},"Gated",[341,430,431],{},"Sequential",",\n",[341,434,435],{},"Parallel"," — validated at construction time.",[396,438,439],{},[338,440,441,443,444,447],{},[354,442,402],{}," parallel fusion and cascaded matching are compositions, and a flat\nlist cannot compose — it can only enumerate, so each new combination becomes\nanother global mode flag. A typed tree of combinators is closed under\ncomposition: any well-typed subtree is itself a stage, and the constructor\nrejects the ill-typed ones and names the offending path (",[341,445,446],{},"PipelineTypeError",").\nErrors a flat list would defer to runtime become unconstructable (Q4).",[369,449,450,453,454,457,458,461,462,425,465,425,468,425,471,474,475,477,478,480,481],{},[372,451,452],{},"Gates are first-class, separate from costs."," 1.x folded gating into the\ncost with ",[341,455,456],{},"GateCost(field).wrap(cost)",". 2.0 makes gates ",[341,459,460],{},"GateProducer","s\n(",[341,463,464],{},"ClassGate",[341,466,467],{},"ScoreGate",[341,469,470],{},"SpatialGate2D",[341,472,473],{},"MotionGate",", …), combines them\nwith ",[341,476,431],{},", and applies them with ",[341,479,428],{},".",[396,482,483],{},[338,484,485,487,488,491,492,494,495,497],{},[354,486,402],{}," binding the gate to the cost couples two independent concerns and\nforces a full ",[341,489,490],{},"(N, M)"," mask even for a per-detection score floor. Split out,\na gate is an algebraic type — per-pair, per-side, or cost-bias — closed under\nconjunction, so gates compose with ",[341,493,431],{},", attach to any cost through\n",[341,496,428],{},", and let the executor allocate the pairwise mask only when a per-pair\ngate demands it (Q5).",[369,499,500,507,508,511,512,515,516,519,520,523,524,526,527,530,531,534,535,538,539],{},[372,501,502,503,506],{},"States moved from the memory to the tracker, and ",[341,504,505],{},"Value"," became a triple.","\n1.x declared states on ",[341,509,510],{},"TrackletMemory(states={...})"," as ",[341,513,514],{},"states.Value(dtype, shape=...)",". 2.0 declares them on ",[341,517,518],{},"Tracker(states={...})"," as a\n",[341,521,522],{},"State(schema, process, observation, init)",". A plain feature cache — what\n1.x ",[341,525,505],{}," was — is ",[341,528,529],{},"Identity"," process + ",[341,532,533],{},"Replace"," observation +\n",[341,536,537],{},"FromDetectionField"," initializer.",[396,540,541],{},[338,542,543,545,546,548,549,552,553,556,557,560,561,563],{},[354,544,402],{}," a dynamics-free ",[341,547,505],{}," can neither predict nor update, which Kalman\nmotion requires. Factoring a state into ",[341,550,551],{},"Process × Observation × Initializer"," spans the range from a plain cache to a Kalman filter by\ncomposition rather than subclassing — the same three slots, filled\ndifferently. The states live on the ",[341,554,555],{},"Tracker"," because it assembles them into\none fixed ",[341,558,559],{},"Tracklets"," type at construction, which gives ",[341,562,406],{}," a\nstable shape and lets the constructor reject type errors before the first\nallocation (Q3, Q7).",[369,565,566,583,584,586,587,590,591,594,595,597,598,600,601,603,604,607,608],{},[372,567,568,571,572,575,576,579,580,582],{},[341,569,570],{},"SimpleTracker"," \u002F ",[341,573,574],{},"StatefulTracker"," → ",[341,577,578],{},"MultiStream","; ",[341,581,393],{}," is pure.","\n1.x bundled tracker and memory in ",[341,585,570],{}," and exposed ",[341,588,589],{},"read()"," \u002F\n",[341,592,593],{},"write()",". In 2.0 a ",[341,596,555],{}," owns no per-stream state — ",[341,599,393],{}," is a pure\nfunction over snapshots — and ",[341,602,578],{}," holds one snapshot per stream\nkey. ",[341,605,606],{},"MultiStream.step(key, detections, ctx)"," is what you call frame to\nframe.",[396,609,610],{},[338,611,612,614,615,617,618,571,620,622,623,625,626,628,629,571,631,634],{},[354,613,402],{}," ",[341,616,393],{}," is now referentially transparent — snapshot in, snapshot out,\nno hidden ",[341,619,589],{},[341,621,593],{},". That one property is what each wrapper needs:\n",[341,624,410],{}," vectorizes only a function with no aliased state, ",[341,627,578],{}," forks\na stream only when nothing is shared behind its back, and autodiff needs a\nfunctional graph to differentiate. 1.x's in-place memory denied all three at\nonce; 2.0 earns all three from a single change, and the stream and id\nbookkeeping move out to ",[341,630,578],{},[341,632,633],{},"BatchTracker"," (Q7, Q10, Q11).",[338,636,637,638,571,641,425,644,571,647,650,651,653],{},"A sixth, smaller change: lifecycle and visibility are now explicit constructor\narguments (",[341,639,640],{},"NoLifecycle",[341,642,643],{},"StandardLifecycle",[341,645,646],{},"IncludeAll",[341,648,649],{},"ConfirmedOnly",")\nrather than implicit behavior of the tracker wrapper. ",[354,652,402],{}," birth, death, and\nre-ID are themselves research variables — SORT confirmation, occlusion windows,\nper-class rules. Making the lifecycle and visibility policies constructor\nparameters keeps the tracker open to new rules yet closed to edits for them: a\nnew policy is a new argument, not a fork (Q8).",[346,655,657],{"id":656},"symbol-map","Symbol map",[659,660,661,674],"table",{},[662,663,664],"thead",{},[665,666,667,671],"tr",{},[668,669,670],"th",{},"1.x",[668,672,673],{},"2.0",[675,676,677,690,702,716,728,740,753,773,788,808,820],"tbody",{},[665,678,679,685],{},[680,681,682],"td",{},[341,683,684],{},"SimpleTracker(tracker=…, memory=…)",[680,686,687],{},[341,688,689],{},"MultiStream(tracker)",[665,691,692,697],{},[680,693,694],{},[341,695,696],{},"MultiStageTracker(fields=…, stages=…)",[680,698,699],{},[341,700,701],{},"Tracker(root=…, states=…, lifecycle=…, visibility=…)",[665,703,704,709],{},[680,705,706],{},[341,707,708],{},"fields=[TensorDictModule(…)]",[680,710,711,712,715],{},"construct ",[341,713,714],{},"Detections(index=…, **fields, batch_size=[M])"," directly",[665,717,718,723],{},[680,719,720],{},[341,721,722],{},"stages.Gate(gate=…, then=[…])",[680,724,725],{},[341,726,727],{},"Gated(gate=…, then=…)",[665,729,730,735],{},[680,731,732],{},[341,733,734],{},"stages.Association(cost=…, assignment=…)",[680,736,737],{},[341,738,739],{},"Pipe(cost=…, assoc=Associate(…))",[665,741,742,747],{},[680,743,744],{},[341,745,746],{},"costs.Cosine(field=…)",[680,748,749,752],{},[341,750,751],{},"costs.Cosine(\"…\")"," (field is positional)",[665,754,755,760],{},[680,756,757],{},[341,758,759],{},"costs.GateCost(f).wrap(cost)",[680,761,762,763,766,767,770,771],{},"a ",[341,764,765],{},"gates.*"," producer (e.g. ",[341,768,769],{},"ClassGate(f)",") under ",[341,772,428],{},[665,774,775,781],{},[680,776,777,780],{},[341,778,779],{},"costs.FieldCost"," (base class)",[680,782,783,784,787],{},"gone; every cost is a small dataclass with a ",[341,785,786],{},"field"," attribute",[665,789,790,795],{},[680,791,792],{},[341,793,794],{},"assignment.Jonker(threshold=…)",[680,796,797,800,801,425,804,807],{},[341,798,799],{},"Associate(Jonker(threshold=…))"," — the backend keeps ",[341,802,803],{},"threshold",[341,805,806],{},"Associate"," wraps it",[665,809,810,815],{},[680,811,812],{},[341,813,814],{},"TrackletMemory(states={k: states.Value(dtype, shape=…)})",[680,816,817],{},[341,818,819],{},"Tracker(states={k: State(schema=TensorSpec(shape, dtype), process=Identity(k), observation=Replace(k), init=FromDetectionField(k))})",[665,821,822,830],{},[680,823,824,571,827],{},[341,825,826],{},"tracker.read()",[341,828,829],{},"tracker.write()",[680,831,832,833,835,836,838],{},"gone — ",[341,834,393],{}," is pure; ",[341,837,578],{}," holds the snapshot",[338,840,841,842,845,846,849,850,853,854,857,858,860],{},"Several costs were also renamed in the move. The two most likely to\nbite: 1.x ",[341,843,844],{},"Softmax"," is now ",[341,847,848],{},"BiSoftmax",", and 1.x ",[341,851,852],{},"BoxIoU"," (which computed CIoU)\nis now ",[341,855,856],{},"BoxCIoU",", with ",[341,859,852],{}," reserved for plain IoU.",[346,862,864],{"id":863},"worked-migration-an-appearance-embedding-tracker","Worked migration: an appearance-embedding tracker",[338,866,867,868,871,872,874],{},"The 1.x tracker below matches detections by ReID embedding alone, gated by\ncategory and a score floor, with the Jonker–Volgenant solver. It is a typical\n1.x builder: field modules at the front, a single ",[341,869,870],{},"Gate → Association"," stage,\nand per-field ",[341,873,505],{}," states on the memory.",[876,877,879],"h3",{"id":878},"before-1x","Before (1.x)",[881,882,887],"pre",{"className":883,"code":884,"language":885,"meta":886,"style":886},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","import torch\nimport unitrack as ut\nfrom tensordict.nn import TensorDictModule\nfrom torch import nn\n\nREID, SCORE, CATEGORY, LABEL = \"reid\", \"score\", \"category\", \"label\"\n\n\ndef _build_field(name, key=None, module=None):\n    key = (name,) if key is None else (key,) if isinstance(key, str) else key\n    return TensorDictModule(module or nn.Identity(), in_keys=[key], out_keys=[name])\n\n\nclass SelectAndFilter(nn.Module):\n    def __init__(self, key_score, key_label, min_score=0.0):\n        super().__init__()\n        self.key_score, self.key_label, self.min_score = key_score, key_label, min_score\n\n    def forward(self, ctx, cs, ds):\n        cs_mask = torch.ones(cs.batch_size[:1], dtype=torch.bool, device=cs.device)\n        ds_mask = ds.get(self.key_score) > self.min_score\n        return cs_mask, ds_mask\n\n\ndef build_embedding_tracker(\n    *,\n    reid_key=\"reid\",\n    threshold=0.9,\n    cost_module=ut.costs.Cosine,\n    category_gate=True,\n    min_score=0.0,\n):\n    cost = cost_module(field=REID)\n    if category_gate:\n        cost = ut.costs.GateCost(CATEGORY).wrap(cost)\n    return ut.SimpleTracker(\n        tracker=ut.MultiStageTracker(\n            fields=[\n                _build_field(REID, reid_key),\n                _build_field(SCORE, \"score\"),\n                _build_field(CATEGORY, \"category\"),\n            ],\n            stages=[\n                ut.stages.Gate(\n                    gate=SelectAndFilter(SCORE, LABEL, min_score=min_score),\n                    then=[\n                        ut.stages.Association(\n                            cost=cost,\n                            assignment=ut.assignment.Jonker(threshold=threshold),\n                        )\n                    ],\n                ),\n            ],\n        ),\n        memory=ut.TrackletMemory(\n            states={\n                SCORE: ut.states.Value(torch.float),\n                CATEGORY: ut.states.Value(torch.long),\n                REID: ut.states.Value(torch.float, shape=(256,)),\n            }\n        ),\n    )\n","python","",[341,888,889,902,916,936,949,956,1022,1027,1032,1074,1137,1190,1195,1200,1222,1260,1275,1319,1324,1353,1417,1452,1466,1471,1476,1487,1495,1511,1524,1546,1559,1571,1576,1597,1609,1646,1659,1676,1687,1705,1725,1744,1750,1760,1778,1807,1817,1834,1846,1875,1881,1887,1893,1898,1904,1921,1932,1962,1991,2032,2038,2043],{"__ignoreMap":886},[890,891,894,898],"span",{"class":892,"line":893},"line",1,[890,895,897],{"class":896},"sVHd0","import",[890,899,901],{"class":900},"su5hD"," torch\n",[890,903,905,907,910,913],{"class":892,"line":904},2,[890,906,897],{"class":896},[890,908,909],{"class":900}," unitrack ",[890,911,912],{"class":896},"as",[890,914,915],{"class":900}," ut\n",[890,917,919,922,925,928,931,933],{"class":892,"line":918},3,[890,920,921],{"class":896},"from",[890,923,924],{"class":900}," tensordict",[890,926,480],{"class":927},"sP7_E",[890,929,930],{"class":900},"nn ",[890,932,897],{"class":896},[890,934,935],{"class":900}," TensorDictModule\n",[890,937,939,941,944,946],{"class":892,"line":938},4,[890,940,921],{"class":896},[890,942,943],{"class":900}," torch ",[890,945,897],{"class":896},[890,947,948],{"class":900}," nn\n",[890,950,952],{"class":892,"line":951},5,[890,953,955],{"emptyLinePlaceholder":954},true,"\n",[890,957,959,963,966,969,971,974,976,979,983,987,991,994,996,998,1001,1003,1005,1007,1010,1012,1014,1016,1019],{"class":892,"line":958},6,[890,960,962],{"class":961},"s_hVV","REID",[890,964,965],{"class":927},",",[890,967,968],{"class":961}," SCORE",[890,970,965],{"class":927},[890,972,973],{"class":961}," CATEGORY",[890,975,965],{"class":927},[890,977,978],{"class":961}," LABEL",[890,980,982],{"class":981},"smGrS"," =",[890,984,986],{"class":985},"sjJ54"," \"",[890,988,990],{"class":989},"s_sjI","reid",[890,992,993],{"class":985},"\"",[890,995,965],{"class":927},[890,997,986],{"class":985},[890,999,1000],{"class":989},"score",[890,1002,993],{"class":985},[890,1004,965],{"class":927},[890,1006,986],{"class":985},[890,1008,1009],{"class":989},"category",[890,1011,993],{"class":985},[890,1013,965],{"class":927},[890,1015,986],{"class":985},[890,1017,1018],{"class":989},"label",[890,1020,1021],{"class":985},"\"\n",[890,1023,1025],{"class":892,"line":1024},7,[890,1026,955],{"emptyLinePlaceholder":954},[890,1028,1030],{"class":892,"line":1029},8,[890,1031,955],{"emptyLinePlaceholder":954},[890,1033,1035,1039,1043,1046,1050,1052,1055,1058,1062,1064,1067,1069,1071],{"class":892,"line":1034},9,[890,1036,1038],{"class":1037},"sbsja","def",[890,1040,1042],{"class":1041},"sGLFI"," _build_field",[890,1044,1045],{"class":927},"(",[890,1047,1049],{"class":1048},"sFwrP","name",[890,1051,965],{"class":927},[890,1053,1054],{"class":1048}," key",[890,1056,1057],{"class":981},"=",[890,1059,1061],{"class":1060},"s39Yj","None",[890,1063,965],{"class":927},[890,1065,1066],{"class":1048}," module",[890,1068,1057],{"class":981},[890,1070,1061],{"class":1060},[890,1072,1073],{"class":927},"):\n",[890,1075,1077,1080,1082,1085,1087,1090,1093,1096,1099,1102,1105,1107,1110,1112,1114,1118,1120,1123,1125,1129,1132,1134],{"class":892,"line":1076},10,[890,1078,1079],{"class":900},"    key ",[890,1081,1057],{"class":981},[890,1083,1084],{"class":927}," (",[890,1086,1049],{"class":900},[890,1088,1089],{"class":927},",)",[890,1091,1092],{"class":896}," if",[890,1094,1095],{"class":900}," key ",[890,1097,1098],{"class":981},"is",[890,1100,1101],{"class":1060}," None",[890,1103,1104],{"class":896}," else",[890,1106,1084],{"class":927},[890,1108,1109],{"class":900},"key",[890,1111,1089],{"class":927},[890,1113,1092],{"class":896},[890,1115,1117],{"class":1116},"sptTA"," isinstance",[890,1119,1045],{"class":927},[890,1121,1109],{"class":1122},"slqww",[890,1124,965],{"class":927},[890,1126,1128],{"class":1127},"sZMiF"," str",[890,1130,1131],{"class":927},")",[890,1133,1104],{"class":896},[890,1135,1136],{"class":900}," key\n",[890,1138,1140,1143,1146,1148,1151,1154,1157,1159,1161,1164,1168,1170,1173,1175,1178,1181,1183,1185,1187],{"class":892,"line":1139},11,[890,1141,1142],{"class":896},"    return",[890,1144,1145],{"class":1122}," TensorDictModule",[890,1147,1045],{"class":927},[890,1149,1150],{"class":1122},"module ",[890,1152,1153],{"class":896},"or",[890,1155,1156],{"class":1122}," nn",[890,1158,480],{"class":927},[890,1160,529],{"class":1122},[890,1162,1163],{"class":927},"(),",[890,1165,1167],{"class":1166},"s99_P"," in_keys",[890,1169,1057],{"class":981},[890,1171,1172],{"class":927},"[",[890,1174,1109],{"class":1122},[890,1176,1177],{"class":927},"],",[890,1179,1180],{"class":1166}," out_keys",[890,1182,1057],{"class":981},[890,1184,1172],{"class":927},[890,1186,1049],{"class":1122},[890,1188,1189],{"class":927},"])\n",[890,1191,1193],{"class":892,"line":1192},12,[890,1194,955],{"emptyLinePlaceholder":954},[890,1196,1198],{"class":892,"line":1197},13,[890,1199,955],{"emptyLinePlaceholder":954},[890,1201,1203,1206,1210,1212,1215,1217,1220],{"class":892,"line":1202},14,[890,1204,1205],{"class":1037},"class",[890,1207,1209],{"class":1208},"sbgvK"," SelectAndFilter",[890,1211,1045],{"class":927},[890,1213,1214],{"class":1208},"nn",[890,1216,480],{"class":927},[890,1218,1219],{"class":1208},"Module",[890,1221,1073],{"class":927},[890,1223,1225,1228,1231,1233,1237,1239,1242,1244,1247,1249,1252,1254,1258],{"class":892,"line":1224},15,[890,1226,1227],{"class":1037},"    def",[890,1229,1230],{"class":1116}," __init__",[890,1232,1045],{"class":927},[890,1234,1236],{"class":1235},"smCYv","self",[890,1238,965],{"class":927},[890,1240,1241],{"class":1048}," key_score",[890,1243,965],{"class":927},[890,1245,1246],{"class":1048}," key_label",[890,1248,965],{"class":927},[890,1250,1251],{"class":1048}," min_score",[890,1253,1057],{"class":981},[890,1255,1257],{"class":1256},"srdBf","0.0",[890,1259,1073],{"class":927},[890,1261,1263,1266,1269,1272],{"class":892,"line":1262},16,[890,1264,1265],{"class":1127},"        super",[890,1267,1268],{"class":927},"().",[890,1270,1271],{"class":1116},"__init__",[890,1273,1274],{"class":927},"()\n",[890,1276,1278,1281,1283,1287,1289,1292,1294,1297,1299,1301,1303,1306,1308,1310,1312,1314,1316],{"class":892,"line":1277},17,[890,1279,1280],{"class":961},"        self",[890,1282,480],{"class":927},[890,1284,1286],{"class":1285},"skxfh","key_score",[890,1288,965],{"class":927},[890,1290,1291],{"class":961}," self",[890,1293,480],{"class":927},[890,1295,1296],{"class":1285},"key_label",[890,1298,965],{"class":927},[890,1300,1291],{"class":961},[890,1302,480],{"class":927},[890,1304,1305],{"class":1285},"min_score",[890,1307,982],{"class":981},[890,1309,1241],{"class":900},[890,1311,965],{"class":927},[890,1313,1246],{"class":900},[890,1315,965],{"class":927},[890,1317,1318],{"class":900}," min_score\n",[890,1320,1322],{"class":892,"line":1321},18,[890,1323,955],{"emptyLinePlaceholder":954},[890,1325,1327,1329,1332,1334,1336,1338,1341,1343,1346,1348,1351],{"class":892,"line":1326},19,[890,1328,1227],{"class":1037},[890,1330,1331],{"class":1041}," forward",[890,1333,1045],{"class":927},[890,1335,1236],{"class":1235},[890,1337,965],{"class":927},[890,1339,1340],{"class":1048}," ctx",[890,1342,965],{"class":927},[890,1344,1345],{"class":1048}," cs",[890,1347,965],{"class":927},[890,1349,1350],{"class":1048}," ds",[890,1352,1073],{"class":927},[890,1354,1356,1359,1361,1364,1366,1369,1371,1374,1376,1379,1382,1385,1387,1390,1392,1395,1397,1400,1402,1405,1407,1409,1411,1414],{"class":892,"line":1355},20,[890,1357,1358],{"class":900},"        cs_mask ",[890,1360,1057],{"class":981},[890,1362,1363],{"class":900}," torch",[890,1365,480],{"class":927},[890,1367,1368],{"class":1122},"ones",[890,1370,1045],{"class":927},[890,1372,1373],{"class":1122},"cs",[890,1375,480],{"class":927},[890,1377,1378],{"class":1285},"batch_size",[890,1380,1381],{"class":927},"[:",[890,1383,1384],{"class":1256},"1",[890,1386,1177],{"class":927},[890,1388,1389],{"class":1166}," dtype",[890,1391,1057],{"class":981},[890,1393,1394],{"class":1122},"torch",[890,1396,480],{"class":927},[890,1398,1399],{"class":1285},"bool",[890,1401,965],{"class":927},[890,1403,1404],{"class":1166}," device",[890,1406,1057],{"class":981},[890,1408,1373],{"class":1122},[890,1410,480],{"class":927},[890,1412,1413],{"class":1285},"device",[890,1415,1416],{"class":927},")\n",[890,1418,1420,1423,1425,1427,1429,1432,1434,1436,1438,1440,1442,1445,1447,1449],{"class":892,"line":1419},21,[890,1421,1422],{"class":900},"        ds_mask ",[890,1424,1057],{"class":981},[890,1426,1350],{"class":900},[890,1428,480],{"class":927},[890,1430,1431],{"class":1122},"get",[890,1433,1045],{"class":927},[890,1435,1236],{"class":961},[890,1437,480],{"class":927},[890,1439,1286],{"class":1285},[890,1441,1131],{"class":927},[890,1443,1444],{"class":981}," >",[890,1446,1291],{"class":961},[890,1448,480],{"class":927},[890,1450,1451],{"class":1285},"min_score\n",[890,1453,1455,1458,1461,1463],{"class":892,"line":1454},22,[890,1456,1457],{"class":896},"        return",[890,1459,1460],{"class":900}," cs_mask",[890,1462,965],{"class":927},[890,1464,1465],{"class":900}," ds_mask\n",[890,1467,1469],{"class":892,"line":1468},23,[890,1470,955],{"emptyLinePlaceholder":954},[890,1472,1474],{"class":892,"line":1473},24,[890,1475,955],{"emptyLinePlaceholder":954},[890,1477,1479,1481,1484],{"class":892,"line":1478},25,[890,1480,1038],{"class":1037},[890,1482,1483],{"class":1041}," build_embedding_tracker",[890,1485,1486],{"class":927},"(\n",[890,1488,1490,1493],{"class":892,"line":1489},26,[890,1491,1492],{"class":981},"    *",[890,1494,432],{"class":900},[890,1496,1498,1501,1503,1505,1507,1509],{"class":892,"line":1497},27,[890,1499,1500],{"class":1048},"    reid_key",[890,1502,1057],{"class":981},[890,1504,993],{"class":985},[890,1506,990],{"class":989},[890,1508,993],{"class":985},[890,1510,432],{"class":927},[890,1512,1514,1517,1519,1522],{"class":892,"line":1513},28,[890,1515,1516],{"class":1048},"    threshold",[890,1518,1057],{"class":981},[890,1520,1521],{"class":1256},"0.9",[890,1523,432],{"class":927},[890,1525,1527,1530,1532,1535,1537,1539,1541,1544],{"class":892,"line":1526},29,[890,1528,1529],{"class":1048},"    cost_module",[890,1531,1057],{"class":981},[890,1533,1534],{"class":900},"ut",[890,1536,480],{"class":927},[890,1538,182],{"class":1285},[890,1540,480],{"class":927},[890,1542,1543],{"class":1285},"Cosine",[890,1545,432],{"class":927},[890,1547,1549,1552,1554,1557],{"class":892,"line":1548},30,[890,1550,1551],{"class":1048},"    category_gate",[890,1553,1057],{"class":981},[890,1555,1556],{"class":1060},"True",[890,1558,432],{"class":927},[890,1560,1562,1565,1567,1569],{"class":892,"line":1561},31,[890,1563,1564],{"class":1048},"    min_score",[890,1566,1057],{"class":981},[890,1568,1257],{"class":1256},[890,1570,432],{"class":927},[890,1572,1574],{"class":892,"line":1573},32,[890,1575,1073],{"class":927},[890,1577,1579,1582,1584,1587,1589,1591,1593,1595],{"class":892,"line":1578},33,[890,1580,1581],{"class":900},"    cost ",[890,1583,1057],{"class":981},[890,1585,1586],{"class":1122}," cost_module",[890,1588,1045],{"class":927},[890,1590,786],{"class":1166},[890,1592,1057],{"class":981},[890,1594,962],{"class":1116},[890,1596,1416],{"class":927},[890,1598,1600,1603,1606],{"class":892,"line":1599},34,[890,1601,1602],{"class":896},"    if",[890,1604,1605],{"class":900}," category_gate",[890,1607,1608],{"class":927},":\n",[890,1610,1612,1615,1617,1620,1622,1624,1626,1629,1631,1634,1637,1640,1642,1644],{"class":892,"line":1611},35,[890,1613,1614],{"class":900},"        cost ",[890,1616,1057],{"class":981},[890,1618,1619],{"class":900}," ut",[890,1621,480],{"class":927},[890,1623,182],{"class":1285},[890,1625,480],{"class":927},[890,1627,1628],{"class":1122},"GateCost",[890,1630,1045],{"class":927},[890,1632,1633],{"class":1116},"CATEGORY",[890,1635,1636],{"class":927},").",[890,1638,1639],{"class":1122},"wrap",[890,1641,1045],{"class":927},[890,1643,203],{"class":1122},[890,1645,1416],{"class":927},[890,1647,1649,1651,1653,1655,1657],{"class":892,"line":1648},36,[890,1650,1142],{"class":896},[890,1652,1619],{"class":900},[890,1654,480],{"class":927},[890,1656,570],{"class":1122},[890,1658,1486],{"class":927},[890,1660,1662,1665,1667,1669,1671,1674],{"class":892,"line":1661},37,[890,1663,1664],{"class":1166},"        tracker",[890,1666,1057],{"class":981},[890,1668,1534],{"class":1122},[890,1670,480],{"class":927},[890,1672,1673],{"class":1122},"MultiStageTracker",[890,1675,1486],{"class":927},[890,1677,1679,1682,1684],{"class":892,"line":1678},38,[890,1680,1681],{"class":1166},"            fields",[890,1683,1057],{"class":981},[890,1685,1686],{"class":927},"[\n",[890,1688,1690,1693,1695,1697,1699,1702],{"class":892,"line":1689},39,[890,1691,1692],{"class":1122},"                _build_field",[890,1694,1045],{"class":927},[890,1696,962],{"class":1116},[890,1698,965],{"class":927},[890,1700,1701],{"class":1122}," reid_key",[890,1703,1704],{"class":927},"),\n",[890,1706,1708,1710,1712,1715,1717,1719,1721,1723],{"class":892,"line":1707},40,[890,1709,1692],{"class":1122},[890,1711,1045],{"class":927},[890,1713,1714],{"class":1116},"SCORE",[890,1716,965],{"class":927},[890,1718,986],{"class":985},[890,1720,1000],{"class":989},[890,1722,993],{"class":985},[890,1724,1704],{"class":927},[890,1726,1728,1730,1732,1734,1736,1738,1740,1742],{"class":892,"line":1727},41,[890,1729,1692],{"class":1122},[890,1731,1045],{"class":927},[890,1733,1633],{"class":1116},[890,1735,965],{"class":927},[890,1737,986],{"class":985},[890,1739,1009],{"class":989},[890,1741,993],{"class":985},[890,1743,1704],{"class":927},[890,1745,1747],{"class":892,"line":1746},42,[890,1748,1749],{"class":927},"            ],\n",[890,1751,1753,1756,1758],{"class":892,"line":1752},43,[890,1754,1755],{"class":1166},"            stages",[890,1757,1057],{"class":981},[890,1759,1686],{"class":927},[890,1761,1763,1766,1768,1771,1773,1776],{"class":892,"line":1762},44,[890,1764,1765],{"class":1122},"                ut",[890,1767,480],{"class":927},[890,1769,1770],{"class":1285},"stages",[890,1772,480],{"class":927},[890,1774,1775],{"class":1122},"Gate",[890,1777,1486],{"class":927},[890,1779,1781,1784,1786,1789,1791,1793,1795,1797,1799,1801,1803,1805],{"class":892,"line":1780},45,[890,1782,1783],{"class":1166},"                    gate",[890,1785,1057],{"class":981},[890,1787,1788],{"class":1122},"SelectAndFilter",[890,1790,1045],{"class":927},[890,1792,1714],{"class":1116},[890,1794,965],{"class":927},[890,1796,978],{"class":1116},[890,1798,965],{"class":927},[890,1800,1251],{"class":1166},[890,1802,1057],{"class":981},[890,1804,1305],{"class":1122},[890,1806,1704],{"class":927},[890,1808,1810,1813,1815],{"class":892,"line":1809},46,[890,1811,1812],{"class":1166},"                    then",[890,1814,1057],{"class":981},[890,1816,1686],{"class":927},[890,1818,1820,1823,1825,1827,1829,1832],{"class":892,"line":1819},47,[890,1821,1822],{"class":1122},"                        ut",[890,1824,480],{"class":927},[890,1826,1770],{"class":1285},[890,1828,480],{"class":927},[890,1830,1831],{"class":1122},"Association",[890,1833,1486],{"class":927},[890,1835,1837,1840,1842,1844],{"class":892,"line":1836},48,[890,1838,1839],{"class":1166},"                            cost",[890,1841,1057],{"class":981},[890,1843,203],{"class":1122},[890,1845,432],{"class":927},[890,1847,1849,1852,1854,1856,1858,1860,1862,1865,1867,1869,1871,1873],{"class":892,"line":1848},49,[890,1850,1851],{"class":1166},"                            assignment",[890,1853,1057],{"class":981},[890,1855,1534],{"class":1122},[890,1857,480],{"class":927},[890,1859,128],{"class":1285},[890,1861,480],{"class":927},[890,1863,1864],{"class":1122},"Jonker",[890,1866,1045],{"class":927},[890,1868,803],{"class":1166},[890,1870,1057],{"class":981},[890,1872,803],{"class":1122},[890,1874,1704],{"class":927},[890,1876,1878],{"class":892,"line":1877},50,[890,1879,1880],{"class":927},"                        )\n",[890,1882,1884],{"class":892,"line":1883},51,[890,1885,1886],{"class":927},"                    ],\n",[890,1888,1890],{"class":892,"line":1889},52,[890,1891,1892],{"class":927},"                ),\n",[890,1894,1896],{"class":892,"line":1895},53,[890,1897,1749],{"class":927},[890,1899,1901],{"class":892,"line":1900},54,[890,1902,1903],{"class":927},"        ),\n",[890,1905,1907,1910,1912,1914,1916,1919],{"class":892,"line":1906},55,[890,1908,1909],{"class":1166},"        memory",[890,1911,1057],{"class":981},[890,1913,1534],{"class":1122},[890,1915,480],{"class":927},[890,1917,1918],{"class":1122},"TrackletMemory",[890,1920,1486],{"class":927},[890,1922,1924,1927,1929],{"class":892,"line":1923},56,[890,1925,1926],{"class":1166},"            states",[890,1928,1057],{"class":981},[890,1930,1931],{"class":927},"{\n",[890,1933,1935,1938,1941,1943,1945,1947,1949,1951,1953,1955,1957,1960],{"class":892,"line":1934},57,[890,1936,1937],{"class":1116},"                SCORE",[890,1939,1940],{"class":927},":",[890,1942,1619],{"class":1122},[890,1944,480],{"class":927},[890,1946,270],{"class":1285},[890,1948,480],{"class":927},[890,1950,505],{"class":1122},[890,1952,1045],{"class":927},[890,1954,1394],{"class":1122},[890,1956,480],{"class":927},[890,1958,1959],{"class":1285},"float",[890,1961,1704],{"class":927},[890,1963,1965,1968,1970,1972,1974,1976,1978,1980,1982,1984,1986,1989],{"class":892,"line":1964},58,[890,1966,1967],{"class":1116},"                CATEGORY",[890,1969,1940],{"class":927},[890,1971,1619],{"class":1122},[890,1973,480],{"class":927},[890,1975,270],{"class":1285},[890,1977,480],{"class":927},[890,1979,505],{"class":1122},[890,1981,1045],{"class":927},[890,1983,1394],{"class":1122},[890,1985,480],{"class":927},[890,1987,1988],{"class":1285},"long",[890,1990,1704],{"class":927},[890,1992,1994,1997,1999,2001,2003,2005,2007,2009,2011,2013,2015,2017,2019,2022,2024,2026,2029],{"class":892,"line":1993},59,[890,1995,1996],{"class":1116},"                REID",[890,1998,1940],{"class":927},[890,2000,1619],{"class":1122},[890,2002,480],{"class":927},[890,2004,270],{"class":1285},[890,2006,480],{"class":927},[890,2008,505],{"class":1122},[890,2010,1045],{"class":927},[890,2012,1394],{"class":1122},[890,2014,480],{"class":927},[890,2016,1959],{"class":1285},[890,2018,965],{"class":927},[890,2020,2021],{"class":1166}," shape",[890,2023,1057],{"class":981},[890,2025,1045],{"class":927},[890,2027,2028],{"class":1256},"256",[890,2030,2031],{"class":927},",)),\n",[890,2033,2035],{"class":892,"line":2034},60,[890,2036,2037],{"class":927},"            }\n",[890,2039,2041],{"class":892,"line":2040},61,[890,2042,1903],{"class":927},[890,2044,2046],{"class":892,"line":2045},62,[890,2047,2048],{"class":927},"    )\n",[876,2050,2052],{"id":2051},"after-20","After (2.0)",[881,2054,2056],{"className":883,"code":2055,"language":885,"meta":886,"style":886},"import torch\nimport unitrack as ut\nfrom unitrack.assignment import Associate, Jonker\nfrom unitrack.costs import Cosine\nfrom unitrack.data import TensorSpec\nfrom unitrack.gates import ClassGate, ScoreGate\nfrom unitrack.lifecycle import IncludeAll, NoLifecycle\nfrom unitrack.pipeline import Gated, Pipe, Sequential\nfrom unitrack.states import FromDetectionField, Identity, Replace, State\n\nREID, SCORE, CATEGORY = \"reid\", \"score\", \"category\"\n\n\ndef _feature_state(name: str, shape: tuple[int, ...], dtype: torch.dtype) -> State:\n    \"\"\"Pure feature cache: no motion model, replace on match, seed from detection.\"\"\"\n    return State(\n        schema=TensorSpec(shape=shape, dtype=dtype),\n        process=Identity(name),\n        observation=Replace(name),\n        init=FromDetectionField(name),\n    )\n\n\ndef build_embedding_tracker(\n    *,\n    threshold: float = 0.1,\n    cost_cls: type = Cosine,\n    category_gate: bool = True,\n    min_score: float = 0.0,\n    reid_dim: int = 256,\n) -> ut.Tracker:\n    gates = [ScoreGate(SCORE, threshold=min_score)]\n    if category_gate:\n        gates.insert(0, ClassGate(CATEGORY))\n    root = Gated(\n        gate=Sequential(gates),\n        then=Pipe(cost=cost_cls(REID), assoc=Associate(Jonker(threshold=threshold))),\n    )\n    return ut.Tracker(\n        root=root,\n        states={\n            REID: _feature_state(REID, (reid_dim,), torch.float32),\n            SCORE: _feature_state(SCORE, (), torch.float32),\n            CATEGORY: _feature_state(CATEGORY, (), torch.int64),\n        },\n        lifecycle=NoLifecycle(),\n        visibility=IncludeAll(),\n    )\n",[341,2057,2058,2064,2074,2096,2112,2128,2149,2170,2196,2227,2231,2267,2271,2275,2332,2345,2353,2382,2397,2412,2427,2431,2435,2439,2447,2453,2469,2486,2502,2517,2534,2548,2576,2584,2610,2621,2636,2683,2687,2699,2711,2720,2752,2778,2804,2809,2821,2832],{"__ignoreMap":886},[890,2059,2060,2062],{"class":892,"line":893},[890,2061,897],{"class":896},[890,2063,901],{"class":900},[890,2065,2066,2068,2070,2072],{"class":892,"line":904},[890,2067,897],{"class":896},[890,2069,909],{"class":900},[890,2071,912],{"class":896},[890,2073,915],{"class":900},[890,2075,2076,2078,2081,2083,2086,2088,2091,2093],{"class":892,"line":918},[890,2077,921],{"class":896},[890,2079,2080],{"class":900}," unitrack",[890,2082,480],{"class":927},[890,2084,2085],{"class":900},"assignment ",[890,2087,897],{"class":896},[890,2089,2090],{"class":900}," Associate",[890,2092,965],{"class":927},[890,2094,2095],{"class":900}," Jonker\n",[890,2097,2098,2100,2102,2104,2107,2109],{"class":892,"line":938},[890,2099,921],{"class":896},[890,2101,2080],{"class":900},[890,2103,480],{"class":927},[890,2105,2106],{"class":900},"costs ",[890,2108,897],{"class":896},[890,2110,2111],{"class":900}," Cosine\n",[890,2113,2114,2116,2118,2120,2123,2125],{"class":892,"line":951},[890,2115,921],{"class":896},[890,2117,2080],{"class":900},[890,2119,480],{"class":927},[890,2121,2122],{"class":900},"data ",[890,2124,897],{"class":896},[890,2126,2127],{"class":900}," TensorSpec\n",[890,2129,2130,2132,2134,2136,2139,2141,2144,2146],{"class":892,"line":958},[890,2131,921],{"class":896},[890,2133,2080],{"class":900},[890,2135,480],{"class":927},[890,2137,2138],{"class":900},"gates ",[890,2140,897],{"class":896},[890,2142,2143],{"class":900}," ClassGate",[890,2145,965],{"class":927},[890,2147,2148],{"class":900}," ScoreGate\n",[890,2150,2151,2153,2155,2157,2160,2162,2165,2167],{"class":892,"line":1024},[890,2152,921],{"class":896},[890,2154,2080],{"class":900},[890,2156,480],{"class":927},[890,2158,2159],{"class":900},"lifecycle ",[890,2161,897],{"class":896},[890,2163,2164],{"class":900}," IncludeAll",[890,2166,965],{"class":927},[890,2168,2169],{"class":900}," NoLifecycle\n",[890,2171,2172,2174,2176,2178,2181,2183,2186,2188,2191,2193],{"class":892,"line":1029},[890,2173,921],{"class":896},[890,2175,2080],{"class":900},[890,2177,480],{"class":927},[890,2179,2180],{"class":900},"pipeline ",[890,2182,897],{"class":896},[890,2184,2185],{"class":900}," Gated",[890,2187,965],{"class":927},[890,2189,2190],{"class":900}," Pipe",[890,2192,965],{"class":927},[890,2194,2195],{"class":900}," Sequential\n",[890,2197,2198,2200,2202,2204,2207,2209,2212,2214,2217,2219,2222,2224],{"class":892,"line":1034},[890,2199,921],{"class":896},[890,2201,2080],{"class":900},[890,2203,480],{"class":927},[890,2205,2206],{"class":900},"states ",[890,2208,897],{"class":896},[890,2210,2211],{"class":900}," FromDetectionField",[890,2213,965],{"class":927},[890,2215,2216],{"class":900}," Identity",[890,2218,965],{"class":927},[890,2220,2221],{"class":900}," Replace",[890,2223,965],{"class":927},[890,2225,2226],{"class":900}," State\n",[890,2228,2229],{"class":892,"line":1076},[890,2230,955],{"emptyLinePlaceholder":954},[890,2232,2233,2235,2237,2239,2241,2243,2245,2247,2249,2251,2253,2255,2257,2259,2261,2263,2265],{"class":892,"line":1139},[890,2234,962],{"class":961},[890,2236,965],{"class":927},[890,2238,968],{"class":961},[890,2240,965],{"class":927},[890,2242,973],{"class":961},[890,2244,982],{"class":981},[890,2246,986],{"class":985},[890,2248,990],{"class":989},[890,2250,993],{"class":985},[890,2252,965],{"class":927},[890,2254,986],{"class":985},[890,2256,1000],{"class":989},[890,2258,993],{"class":985},[890,2260,965],{"class":927},[890,2262,986],{"class":985},[890,2264,1009],{"class":989},[890,2266,1021],{"class":985},[890,2268,2269],{"class":892,"line":1192},[890,2270,955],{"emptyLinePlaceholder":954},[890,2272,2273],{"class":892,"line":1197},[890,2274,955],{"emptyLinePlaceholder":954},[890,2276,2277,2279,2282,2284,2286,2288,2290,2292,2294,2296,2299,2301,2304,2306,2309,2311,2313,2315,2317,2319,2322,2324,2327,2330],{"class":892,"line":1202},[890,2278,1038],{"class":1037},[890,2280,2281],{"class":1041}," _feature_state",[890,2283,1045],{"class":927},[890,2285,1049],{"class":1048},[890,2287,1940],{"class":927},[890,2289,1128],{"class":1127},[890,2291,965],{"class":927},[890,2293,2021],{"class":1048},[890,2295,1940],{"class":927},[890,2297,2298],{"class":900}," tuple",[890,2300,1172],{"class":927},[890,2302,2303],{"class":1127},"int",[890,2305,965],{"class":927},[890,2307,2308],{"class":961}," ...",[890,2310,1177],{"class":927},[890,2312,1389],{"class":1048},[890,2314,1940],{"class":927},[890,2316,1363],{"class":900},[890,2318,480],{"class":927},[890,2320,2321],{"class":1285},"dtype",[890,2323,1131],{"class":927},[890,2325,2326],{"class":927}," ->",[890,2328,2329],{"class":900}," State",[890,2331,1608],{"class":927},[890,2333,2334,2338,2342],{"class":892,"line":1224},[890,2335,2337],{"class":2336},"s2W-s","    \"\"\"",[890,2339,2341],{"class":2340},"sithA","Pure feature cache: no motion model, replace on match, seed from detection.",[890,2343,2344],{"class":2336},"\"\"\"\n",[890,2346,2347,2349,2351],{"class":892,"line":1262},[890,2348,1142],{"class":896},[890,2350,2329],{"class":1122},[890,2352,1486],{"class":927},[890,2354,2355,2358,2360,2363,2365,2368,2370,2372,2374,2376,2378,2380],{"class":892,"line":1277},[890,2356,2357],{"class":1166},"        schema",[890,2359,1057],{"class":981},[890,2361,2362],{"class":1122},"TensorSpec",[890,2364,1045],{"class":927},[890,2366,2367],{"class":1166},"shape",[890,2369,1057],{"class":981},[890,2371,2367],{"class":1122},[890,2373,965],{"class":927},[890,2375,1389],{"class":1166},[890,2377,1057],{"class":981},[890,2379,2321],{"class":1122},[890,2381,1704],{"class":927},[890,2383,2384,2387,2389,2391,2393,2395],{"class":892,"line":1321},[890,2385,2386],{"class":1166},"        process",[890,2388,1057],{"class":981},[890,2390,529],{"class":1122},[890,2392,1045],{"class":927},[890,2394,1049],{"class":1122},[890,2396,1704],{"class":927},[890,2398,2399,2402,2404,2406,2408,2410],{"class":892,"line":1326},[890,2400,2401],{"class":1166},"        observation",[890,2403,1057],{"class":981},[890,2405,533],{"class":1122},[890,2407,1045],{"class":927},[890,2409,1049],{"class":1122},[890,2411,1704],{"class":927},[890,2413,2414,2417,2419,2421,2423,2425],{"class":892,"line":1355},[890,2415,2416],{"class":1166},"        init",[890,2418,1057],{"class":981},[890,2420,537],{"class":1122},[890,2422,1045],{"class":927},[890,2424,1049],{"class":1122},[890,2426,1704],{"class":927},[890,2428,2429],{"class":892,"line":1419},[890,2430,2048],{"class":927},[890,2432,2433],{"class":892,"line":1454},[890,2434,955],{"emptyLinePlaceholder":954},[890,2436,2437],{"class":892,"line":1468},[890,2438,955],{"emptyLinePlaceholder":954},[890,2440,2441,2443,2445],{"class":892,"line":1473},[890,2442,1038],{"class":1037},[890,2444,1483],{"class":1041},[890,2446,1486],{"class":927},[890,2448,2449,2451],{"class":892,"line":1478},[890,2450,1492],{"class":981},[890,2452,432],{"class":900},[890,2454,2455,2457,2459,2462,2464,2467],{"class":892,"line":1489},[890,2456,1516],{"class":1048},[890,2458,1940],{"class":927},[890,2460,2461],{"class":1127}," float",[890,2463,982],{"class":981},[890,2465,2466],{"class":1256}," 0.1",[890,2468,432],{"class":927},[890,2470,2471,2474,2476,2479,2481,2484],{"class":892,"line":1497},[890,2472,2473],{"class":1048},"    cost_cls",[890,2475,1940],{"class":927},[890,2477,2478],{"class":1127}," type",[890,2480,982],{"class":981},[890,2482,2483],{"class":900}," Cosine",[890,2485,432],{"class":927},[890,2487,2488,2490,2492,2495,2497,2500],{"class":892,"line":1513},[890,2489,1551],{"class":1048},[890,2491,1940],{"class":927},[890,2493,2494],{"class":1127}," bool",[890,2496,982],{"class":981},[890,2498,2499],{"class":1060}," True",[890,2501,432],{"class":927},[890,2503,2504,2506,2508,2510,2512,2515],{"class":892,"line":1526},[890,2505,1564],{"class":1048},[890,2507,1940],{"class":927},[890,2509,2461],{"class":1127},[890,2511,982],{"class":981},[890,2513,2514],{"class":1256}," 0.0",[890,2516,432],{"class":927},[890,2518,2519,2522,2524,2527,2529,2532],{"class":892,"line":1548},[890,2520,2521],{"class":1048},"    reid_dim",[890,2523,1940],{"class":927},[890,2525,2526],{"class":1127}," int",[890,2528,982],{"class":981},[890,2530,2531],{"class":1256}," 256",[890,2533,432],{"class":927},[890,2535,2536,2538,2540,2542,2544,2546],{"class":892,"line":1561},[890,2537,1131],{"class":927},[890,2539,2326],{"class":927},[890,2541,1619],{"class":900},[890,2543,480],{"class":927},[890,2545,555],{"class":1285},[890,2547,1608],{"class":927},[890,2549,2550,2553,2555,2558,2560,2562,2564,2566,2569,2571,2573],{"class":892,"line":1573},[890,2551,2552],{"class":900},"    gates ",[890,2554,1057],{"class":981},[890,2556,2557],{"class":927}," [",[890,2559,467],{"class":1122},[890,2561,1045],{"class":927},[890,2563,1714],{"class":1116},[890,2565,965],{"class":927},[890,2567,2568],{"class":1166}," threshold",[890,2570,1057],{"class":981},[890,2572,1305],{"class":1122},[890,2574,2575],{"class":927},")]\n",[890,2577,2578,2580,2582],{"class":892,"line":1578},[890,2579,1602],{"class":896},[890,2581,1605],{"class":900},[890,2583,1608],{"class":927},[890,2585,2586,2589,2591,2594,2596,2599,2601,2603,2605,2607],{"class":892,"line":1599},[890,2587,2588],{"class":900},"        gates",[890,2590,480],{"class":927},[890,2592,2593],{"class":1122},"insert",[890,2595,1045],{"class":927},[890,2597,2598],{"class":1256},"0",[890,2600,965],{"class":927},[890,2602,2143],{"class":1122},[890,2604,1045],{"class":927},[890,2606,1633],{"class":1116},[890,2608,2609],{"class":927},"))\n",[890,2611,2612,2615,2617,2619],{"class":892,"line":1611},[890,2613,2614],{"class":900},"    root ",[890,2616,1057],{"class":981},[890,2618,2185],{"class":1122},[890,2620,1486],{"class":927},[890,2622,2623,2626,2628,2630,2632,2634],{"class":892,"line":1648},[890,2624,2625],{"class":1166},"        gate",[890,2627,1057],{"class":981},[890,2629,431],{"class":1122},[890,2631,1045],{"class":927},[890,2633,224],{"class":1122},[890,2635,1704],{"class":927},[890,2637,2638,2641,2643,2645,2647,2649,2651,2654,2656,2658,2661,2664,2666,2668,2670,2672,2674,2676,2678,2680],{"class":892,"line":1661},[890,2639,2640],{"class":1166},"        then",[890,2642,1057],{"class":981},[890,2644,424],{"class":1122},[890,2646,1045],{"class":927},[890,2648,203],{"class":1166},[890,2650,1057],{"class":981},[890,2652,2653],{"class":1122},"cost_cls",[890,2655,1045],{"class":927},[890,2657,962],{"class":1116},[890,2659,2660],{"class":927},"),",[890,2662,2663],{"class":1166}," assoc",[890,2665,1057],{"class":981},[890,2667,806],{"class":1122},[890,2669,1045],{"class":927},[890,2671,1864],{"class":1122},[890,2673,1045],{"class":927},[890,2675,803],{"class":1166},[890,2677,1057],{"class":981},[890,2679,803],{"class":1122},[890,2681,2682],{"class":927},"))),\n",[890,2684,2685],{"class":892,"line":1678},[890,2686,2048],{"class":927},[890,2688,2689,2691,2693,2695,2697],{"class":892,"line":1689},[890,2690,1142],{"class":896},[890,2692,1619],{"class":900},[890,2694,480],{"class":927},[890,2696,555],{"class":1122},[890,2698,1486],{"class":927},[890,2700,2701,2704,2706,2709],{"class":892,"line":1707},[890,2702,2703],{"class":1166},"        root",[890,2705,1057],{"class":981},[890,2707,2708],{"class":1122},"root",[890,2710,432],{"class":927},[890,2712,2713,2716,2718],{"class":892,"line":1727},[890,2714,2715],{"class":1166},"        states",[890,2717,1057],{"class":981},[890,2719,1931],{"class":927},[890,2721,2722,2725,2727,2729,2731,2733,2735,2737,2740,2743,2745,2747,2750],{"class":892,"line":1746},[890,2723,2724],{"class":1116},"            REID",[890,2726,1940],{"class":927},[890,2728,2281],{"class":1122},[890,2730,1045],{"class":927},[890,2732,962],{"class":1116},[890,2734,965],{"class":927},[890,2736,1084],{"class":927},[890,2738,2739],{"class":1122},"reid_dim",[890,2741,2742],{"class":927},",),",[890,2744,1363],{"class":1122},[890,2746,480],{"class":927},[890,2748,2749],{"class":1285},"float32",[890,2751,1704],{"class":927},[890,2753,2754,2757,2759,2761,2763,2765,2767,2770,2772,2774,2776],{"class":892,"line":1752},[890,2755,2756],{"class":1116},"            SCORE",[890,2758,1940],{"class":927},[890,2760,2281],{"class":1122},[890,2762,1045],{"class":927},[890,2764,1714],{"class":1116},[890,2766,965],{"class":927},[890,2768,2769],{"class":927}," (),",[890,2771,1363],{"class":1122},[890,2773,480],{"class":927},[890,2775,2749],{"class":1285},[890,2777,1704],{"class":927},[890,2779,2780,2783,2785,2787,2789,2791,2793,2795,2797,2799,2802],{"class":892,"line":1762},[890,2781,2782],{"class":1116},"            CATEGORY",[890,2784,1940],{"class":927},[890,2786,2281],{"class":1122},[890,2788,1045],{"class":927},[890,2790,1633],{"class":1116},[890,2792,965],{"class":927},[890,2794,2769],{"class":927},[890,2796,1363],{"class":1122},[890,2798,480],{"class":927},[890,2800,2801],{"class":1285},"int64",[890,2803,1704],{"class":927},[890,2805,2806],{"class":892,"line":1780},[890,2807,2808],{"class":927},"        },\n",[890,2810,2811,2814,2816,2818],{"class":892,"line":1809},[890,2812,2813],{"class":1166},"        lifecycle",[890,2815,1057],{"class":981},[890,2817,640],{"class":1122},[890,2819,2820],{"class":927},"(),\n",[890,2822,2823,2826,2828,2830],{"class":892,"line":1819},[890,2824,2825],{"class":1166},"        visibility",[890,2827,1057],{"class":981},[890,2829,646],{"class":1122},[890,2831,2820],{"class":927},[890,2833,2834],{"class":892,"line":1836},[890,2835,2048],{"class":927},[876,2837,2839],{"id":2838},"what-dissolved-line-by-line","What dissolved, line by line",[2841,2842,2843,2867,2887,2914,2948],"ul",{},[369,2844,2845,2855,2856,2858,2859,2862,2863,2866],{},[372,2846,2847,2850,2851,2854],{},[341,2848,2849],{},"_build_field"," and the ",[341,2852,2853],{},"fields=[…]"," list."," The front-of-pipeline field\nselection has no analogue in 2.0. You no longer rename tensors inside the\ntracker; you name them when you build the ",[341,2857,377],{}," record (next section).\nThe ",[341,2860,2861],{},"reid_key"," parameter — which existed only to rename an input tensor to\n",[341,2864,2865],{},"\"reid\""," — disappears with it.",[369,2868,2869,2874,2875,2877,2878,2880,2881,2883,2884,2886],{},[372,2870,2871,480],{},[341,2872,2873],{},"GateCost(CATEGORY).wrap(cost)"," Category gating is now a ",[341,2876,464],{},", a\n",[341,2879,460],{}," that emits a per-pair equality mask. It composes with the\nscore gate through ",[341,2882,431],{}," and is applied to the cost stage by ",[341,2885,428],{},",\ninstead of being woven into the cost object.",[369,2888,2889,2893,2894,2897,2898,2901,2902,2905,2906,2909,2910,2913],{},[372,2890,2891,480],{},[341,2892,1788],{}," Its score branch (",[341,2895,2896],{},"ds_mask = score > min_score",")\nbecomes ",[341,2899,2900],{},"ScoreGate(SCORE, threshold=min_score)",". Its ",[341,2903,2904],{},"cs_mask"," was always\nall-True, i.e. a no-op on the tracklet side, so nothing replaces it. If you\n",[354,2907,2908],{},"did"," filter tracklets by status here, that is now a ",[341,2911,2912],{},"Filter(StatusFilter(…), on=\"cs\")"," node.",[369,2915,2916,2921,2922,2925,2926,2928,2929,2931,2932,2934,2935,2937,2938,2940,2941,2944,2945,2947],{},[372,2917,2918,480],{},[341,2919,2920],{},"states.Value(dtype, shape=…)"," Each becomes a ",[341,2923,2924],{},"State",". A ",[341,2927,505],{}," was a\ncache with no dynamics, which is exactly ",[341,2930,529],{}," (no predict) + ",[341,2933,533],{},"\n(overwrite matched rows) + ",[341,2936,537],{}," (seed new rows). ",[341,2939,2362],{},"\ncarries the same ",[341,2942,2943],{},"(shape, dtype)"," the 1.x ",[341,2946,505],{}," did.",[369,2949,2950,2956,2957,2959,2960,407,2962,2964,2965,2967],{},[372,2951,2952,407,2954,480],{},[341,2953,570],{},[341,2955,1918],{}," The builder now returns a bare\n",[341,2958,555],{},". The per-stream snapshot that ",[341,2961,570],{},[341,2963,1918],{},"\nused to own moves into ",[341,2966,578],{},", created at the call site.",[876,2969,2971],{"id":2970},"feeding-the-tracker","Feeding the tracker",[338,2973,2974,2975,2978,2979,2981,2982,2984,2985,2987,2988,2991,2992,2994,2995,2997,2998,3001,3002,3005],{},"In 1.x, an input module (multiformer's ",[341,2976,2977],{},"TrackerInput",") produced a dict of\ntensors, the ",[341,2980,2853],{}," modules selected from it, and ",[341,2983,570],{}," handled\nread\u002Fwrite. In 2.0 you build a ",[341,2986,377],{}," record and call ",[341,2989,2990],{},"MultiStream.step",".\nThe record needs a reserved ",[341,2993,125],{}," field (",[341,2996,2801],{},", shape ",[341,2999,3000],{},"(M,)",") that threads\nyour detection ordering through to the ",[341,3003,3004],{},"MatchOutcome","; the remaining fields are\nthe ones your states read.",[881,3007,3009],{"className":883,"code":3008,"language":885,"meta":886,"style":886},"from unitrack.data import Detections, FrameContext\n\ntracker = build_embedding_tracker()\nms = ut.MultiStream(tracker)\n\nfor frame_idx, frame in enumerate(stream):  # your per-frame source\n    reid = frame[\"reid\"]  # (M, 256) float32\n    score = frame[\"score\"]  # (M,)     float32\n    category = frame[\"category\"]  # (M,)     int64\n    m = score.shape[0]\n\n    det = Detections(\n        index=torch.arange(m, dtype=torch.int64, device=score.device),\n        reid=reid,\n        score=score,\n        category=category,\n        batch_size=[m],\n    )\n    res = ms.step(0, det, FrameContext.make(frame_idx, stream_key=0))\n\n    # res.ids: int64 tracklet IDs visible this frame (per the Visibility policy).\n    # res.match.matched_pairs: (K, 2) [tracklet_row, detection_row]; recover the\n    # original detection via det.index[pair[1]], and stable identity via\n    # res.snapshot.id. See the MatchOutcome reference for the residual indices.\n    for tracklet_row, det_row in res.match.matched_pairs.tolist():\n        det_id = det.index[det_row].item()\n        ...\n",[341,3010,3011,3031,3035,3046,3065,3069,3100,3124,3146,3168,3189,3193,3204,3249,3260,3271,3282,3296,3300,3349,3353,3358,3363,3368,3373,3408,3434],{"__ignoreMap":886},[890,3012,3013,3015,3017,3019,3021,3023,3026,3028],{"class":892,"line":893},[890,3014,921],{"class":896},[890,3016,2080],{"class":900},[890,3018,480],{"class":927},[890,3020,2122],{"class":900},[890,3022,897],{"class":896},[890,3024,3025],{"class":900}," Detections",[890,3027,965],{"class":927},[890,3029,3030],{"class":900}," FrameContext\n",[890,3032,3033],{"class":892,"line":904},[890,3034,955],{"emptyLinePlaceholder":954},[890,3036,3037,3040,3042,3044],{"class":892,"line":918},[890,3038,3039],{"class":900},"tracker ",[890,3041,1057],{"class":981},[890,3043,1483],{"class":1122},[890,3045,1274],{"class":927},[890,3047,3048,3051,3053,3055,3057,3059,3061,3063],{"class":892,"line":938},[890,3049,3050],{"class":900},"ms ",[890,3052,1057],{"class":981},[890,3054,1619],{"class":900},[890,3056,480],{"class":927},[890,3058,578],{"class":1122},[890,3060,1045],{"class":927},[890,3062,173],{"class":1122},[890,3064,1416],{"class":927},[890,3066,3067],{"class":892,"line":951},[890,3068,955],{"emptyLinePlaceholder":954},[890,3070,3071,3074,3077,3079,3082,3085,3088,3090,3093,3096],{"class":892,"line":958},[890,3072,3073],{"class":896},"for",[890,3075,3076],{"class":900}," frame_idx",[890,3078,965],{"class":927},[890,3080,3081],{"class":900}," frame ",[890,3083,3084],{"class":896},"in",[890,3086,3087],{"class":1116}," enumerate",[890,3089,1045],{"class":927},[890,3091,3092],{"class":1122},"stream",[890,3094,3095],{"class":927},"):",[890,3097,3099],{"class":3098},"sutJx","  # your per-frame source\n",[890,3101,3102,3105,3107,3110,3112,3114,3116,3118,3121],{"class":892,"line":1024},[890,3103,3104],{"class":900},"    reid ",[890,3106,1057],{"class":981},[890,3108,3109],{"class":900}," frame",[890,3111,1172],{"class":927},[890,3113,993],{"class":985},[890,3115,990],{"class":989},[890,3117,993],{"class":985},[890,3119,3120],{"class":927},"]",[890,3122,3123],{"class":3098},"  # (M, 256) float32\n",[890,3125,3126,3129,3131,3133,3135,3137,3139,3141,3143],{"class":892,"line":1029},[890,3127,3128],{"class":900},"    score ",[890,3130,1057],{"class":981},[890,3132,3109],{"class":900},[890,3134,1172],{"class":927},[890,3136,993],{"class":985},[890,3138,1000],{"class":989},[890,3140,993],{"class":985},[890,3142,3120],{"class":927},[890,3144,3145],{"class":3098},"  # (M,)     float32\n",[890,3147,3148,3151,3153,3155,3157,3159,3161,3163,3165],{"class":892,"line":1034},[890,3149,3150],{"class":900},"    category ",[890,3152,1057],{"class":981},[890,3154,3109],{"class":900},[890,3156,1172],{"class":927},[890,3158,993],{"class":985},[890,3160,1009],{"class":989},[890,3162,993],{"class":985},[890,3164,3120],{"class":927},[890,3166,3167],{"class":3098},"  # (M,)     int64\n",[890,3169,3170,3173,3175,3178,3180,3182,3184,3186],{"class":892,"line":1076},[890,3171,3172],{"class":900},"    m ",[890,3174,1057],{"class":981},[890,3176,3177],{"class":900}," score",[890,3179,480],{"class":927},[890,3181,2367],{"class":1285},[890,3183,1172],{"class":927},[890,3185,2598],{"class":1256},[890,3187,3188],{"class":927},"]\n",[890,3190,3191],{"class":892,"line":1139},[890,3192,955],{"emptyLinePlaceholder":954},[890,3194,3195,3198,3200,3202],{"class":892,"line":1192},[890,3196,3197],{"class":900},"    det ",[890,3199,1057],{"class":981},[890,3201,3025],{"class":1122},[890,3203,1486],{"class":927},[890,3205,3206,3209,3211,3213,3215,3218,3220,3223,3225,3227,3229,3231,3233,3235,3237,3239,3241,3243,3245,3247],{"class":892,"line":1197},[890,3207,3208],{"class":1166},"        index",[890,3210,1057],{"class":981},[890,3212,1394],{"class":1122},[890,3214,480],{"class":927},[890,3216,3217],{"class":1122},"arange",[890,3219,1045],{"class":927},[890,3221,3222],{"class":1122},"m",[890,3224,965],{"class":927},[890,3226,1389],{"class":1166},[890,3228,1057],{"class":981},[890,3230,1394],{"class":1122},[890,3232,480],{"class":927},[890,3234,2801],{"class":1285},[890,3236,965],{"class":927},[890,3238,1404],{"class":1166},[890,3240,1057],{"class":981},[890,3242,1000],{"class":1122},[890,3244,480],{"class":927},[890,3246,1413],{"class":1285},[890,3248,1704],{"class":927},[890,3250,3251,3254,3256,3258],{"class":892,"line":1202},[890,3252,3253],{"class":1166},"        reid",[890,3255,1057],{"class":981},[890,3257,990],{"class":1122},[890,3259,432],{"class":927},[890,3261,3262,3265,3267,3269],{"class":892,"line":1224},[890,3263,3264],{"class":1166},"        score",[890,3266,1057],{"class":981},[890,3268,1000],{"class":1122},[890,3270,432],{"class":927},[890,3272,3273,3276,3278,3280],{"class":892,"line":1262},[890,3274,3275],{"class":1166},"        category",[890,3277,1057],{"class":981},[890,3279,1009],{"class":1122},[890,3281,432],{"class":927},[890,3283,3284,3287,3289,3291,3293],{"class":892,"line":1277},[890,3285,3286],{"class":1166},"        batch_size",[890,3288,1057],{"class":981},[890,3290,1172],{"class":927},[890,3292,3222],{"class":1122},[890,3294,3295],{"class":927},"],\n",[890,3297,3298],{"class":892,"line":1321},[890,3299,2048],{"class":927},[890,3301,3302,3305,3307,3310,3312,3314,3316,3318,3320,3323,3325,3328,3330,3333,3335,3338,3340,3343,3345,3347],{"class":892,"line":1326},[890,3303,3304],{"class":900},"    res ",[890,3306,1057],{"class":981},[890,3308,3309],{"class":900}," ms",[890,3311,480],{"class":927},[890,3313,393],{"class":1122},[890,3315,1045],{"class":927},[890,3317,2598],{"class":1256},[890,3319,965],{"class":927},[890,3321,3322],{"class":1122}," det",[890,3324,965],{"class":927},[890,3326,3327],{"class":1122}," FrameContext",[890,3329,480],{"class":927},[890,3331,3332],{"class":1122},"make",[890,3334,1045],{"class":927},[890,3336,3337],{"class":1122},"frame_idx",[890,3339,965],{"class":927},[890,3341,3342],{"class":1166}," stream_key",[890,3344,1057],{"class":981},[890,3346,2598],{"class":1256},[890,3348,2609],{"class":927},[890,3350,3351],{"class":892,"line":1355},[890,3352,955],{"emptyLinePlaceholder":954},[890,3354,3355],{"class":892,"line":1419},[890,3356,3357],{"class":3098},"    # res.ids: int64 tracklet IDs visible this frame (per the Visibility policy).\n",[890,3359,3360],{"class":892,"line":1454},[890,3361,3362],{"class":3098},"    # res.match.matched_pairs: (K, 2) [tracklet_row, detection_row]; recover the\n",[890,3364,3365],{"class":892,"line":1468},[890,3366,3367],{"class":3098},"    # original detection via det.index[pair[1]], and stable identity via\n",[890,3369,3370],{"class":892,"line":1473},[890,3371,3372],{"class":3098},"    # res.snapshot.id. See the MatchOutcome reference for the residual indices.\n",[890,3374,3375,3378,3381,3383,3386,3388,3391,3393,3395,3397,3400,3402,3405],{"class":892,"line":1478},[890,3376,3377],{"class":896},"    for",[890,3379,3380],{"class":900}," tracklet_row",[890,3382,965],{"class":927},[890,3384,3385],{"class":900}," det_row ",[890,3387,3084],{"class":896},[890,3389,3390],{"class":900}," res",[890,3392,480],{"class":927},[890,3394,215],{"class":1285},[890,3396,480],{"class":927},[890,3398,3399],{"class":1285},"matched_pairs",[890,3401,480],{"class":927},[890,3403,3404],{"class":1122},"tolist",[890,3406,3407],{"class":927},"():\n",[890,3409,3410,3413,3415,3417,3419,3421,3423,3426,3429,3432],{"class":892,"line":1489},[890,3411,3412],{"class":900},"        det_id ",[890,3414,1057],{"class":981},[890,3416,3322],{"class":900},[890,3418,480],{"class":927},[890,3420,125],{"class":1285},[890,3422,1172],{"class":927},[890,3424,3425],{"class":1285},"det_row",[890,3427,3428],{"class":927},"].",[890,3430,3431],{"class":1122},"item",[890,3433,1274],{"class":927},[890,3435,3436],{"class":892,"line":1497},[890,3437,3438],{"class":961},"        ...\n",[338,3440,3441,3442,3445,3446,3449,3450,3452],{},"Preprocessing that produced detection tensors in 1.x is unaffected.\nmultiformer's ",[341,3443,3444],{},"MaskToBoxes",", for instance, is a plain tensor op upstream of the\ntracker; its ",[341,3447,3448],{},"(N, 4)"," output now becomes a ",[341,3451,377],{}," field instead of an\nentry in the dict the field modules read.",[346,3454,3456],{"id":3455},"behavioral-notes","Behavioral notes",[2841,3458,3459,3505,3531],{},[369,3460,3461,3464,3465,3467,3468,3471,3472,3475,3476,3479,3480,3482,3483,3486,3487,3490,3491,3493,3494,3490,3497,3500,3501,3504],{},[372,3462,3463],{},"Re-derive thresholds; do not copy the 1.x number."," In 2.0, ",[341,3466,1543],{},"\nreturns ",[341,3469,3470],{},"1 − cosine_similarity"," (a distance), ",[341,3473,3474],{},"Jonker(threshold=t)"," masks\npairs whose cost is strictly above ",[341,3477,3478],{},"t",", and ",[341,3481,806],{}," keeps matched pairs\nwith ",[341,3484,3485],{},"cost \u003C= t",". So a 1.x similarity ",[354,3488,3489],{},"floor"," of ",[341,3492,1521],{}," corresponds to a 2.0\ndistance ",[354,3495,3496],{},"ceiling",[341,3498,3499],{},"0.1"," — hence ",[341,3502,3503],{},"threshold=0.1"," in the migrated builder.\nCheck the cost's range and direction before reusing a tuned value.",[369,3506,3507,3517,3518,3521,3522,3525,3526,3530],{},[372,3508,3509,3512,3513,3516],{},[341,3510,3511],{},"NoLifecycle()"," + ",[341,3514,3515],{},"IncludeAll()"," reproduces the 1.x embedding tracker."," It\nhad no birth\u002Fdeath logic — every tracklet matched and every ID was visible.\nTo add SORT-style confirmation, switch to ",[341,3519,3520],{},"StandardLifecycle(min_hits, max_age)","\nand ",[341,3523,3524],{},"ConfirmedOnly()","; the ",[3527,3528,3529],"a",{"href":35},"recipes\u002Fsort"," recipe shows the full form.",[369,3532,3533,3538,3539,3541,3542,3544,3545,3547,3548,3551],{},[372,3534,3535,3537],{},[341,3536,377],{}," is immutable and validated."," Construction checks that ",[341,3540,125],{},"\nis present, ",[341,3543,2801],{},", and shape ",[341,3546,3000],{},". Use ",[341,3549,3550],{},"Detections.empty()"," for an\nempty-frame placeholder.",[346,3553,3555],{"id":3554},"see-also","See also",[2841,3557,3558,3566,3576],{},[369,3559,3560,3565],{},[372,3561,3562],{},[3527,3563,3564],{"href":120},"notebooks\u002Ftutorials\u002Fmigration"," — this migration run as an\ninteractive notebook: it ports the tracker above and then showcases the new\n2.0 possibilities (parallel fusion, cascaded matching, lifecycle, and\ndifferentiable matching) on detections from a real lightweight detector.",[369,3567,3568,3571,3572,3575],{},[3527,3569,3570],{"href":31},"recipes\u002Foverlap_tracker"," — the closest sibling: a single-stage class-\nand score-gated matcher, ported from the 1.x ",[341,3573,3574],{},"models.overlap"," builder.",[369,3577,3578,3580,3581,425,3583,3585],{},[3527,3579,3529],{"href":35}," — a stateful IoU + Kalman tracker, showing\n",[341,3582,643],{},[341,3584,649],{},", and a Kalman state.",[3587,3588,3589],"style",{},"html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sFwrP, html code.shiki .sFwrP{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#24292E;--shiki-default-font-style:inherit;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .slqww, html code.shiki .slqww{--shiki-light:#6182B8;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .smCYv, html code.shiki .smCYv{--shiki-light:#E53935;--shiki-light-font-style:italic;--shiki-default:#24292E;--shiki-default-font-style:inherit;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2W-s, html code.shiki .s2W-s{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#032F62;--shiki-default-font-style:inherit;--shiki-dark:#9ECBFF;--shiki-dark-font-style:inherit}html pre.shiki code .sithA, html code.shiki .sithA{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#032F62;--shiki-default-font-style:inherit;--shiki-dark:#9ECBFF;--shiki-dark-font-style:inherit}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}",{"title":886,"searchDepth":918,"depth":918,"links":3591},[3592,3593,3594,3595,3601,3602],{"id":348,"depth":904,"text":349},{"id":360,"depth":904,"text":361},{"id":656,"depth":904,"text":657},{"id":863,"depth":904,"text":864,"children":3596},[3597,3598,3599,3600],{"id":878,"depth":918,"text":879},{"id":2051,"depth":918,"text":2052},{"id":2838,"depth":918,"text":2839},{"id":2970,"depth":918,"text":2971},{"id":3455,"depth":904,"text":3456},{"id":3554,"depth":904,"text":3555},"unitrack 2.0 is a hard break. There are no compatibility shims, and a tracker\nwritten against 1.x will not import unchanged: the primitives were re-cut around\na typed data model and a composable stage tree. This page maps the 1.x surface\nonto 2.0 and then migrates a real 1.x tracker — an appearance-embedding matcher\n— end to end.","md",{},{"title":45,"description":3603},"pVHCW89J5gZSueA5UNHN5kiYv35cM4koYY7aWMgcP-w",{},1785139881971]