x2q commited on
Commit
9285f34
Β·
verified Β·
1 Parent(s): 694fd97

SpeedNet v5: corrected 790 m indoor supervision, multi-seed selection, per-mode evaluation, four GPS-verified demo videos

Browse files
.gitattributes CHANGED
@@ -35,3 +35,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  assets/example_atv.png filter=lfs diff=lfs merge=lfs -text
37
  assets/demo_bestlap.mp4 filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  assets/example_atv.png filter=lfs diff=lfs merge=lfs -text
37
  assets/demo_bestlap.mp4 filter=lfs diff=lfs merge=lfs -text
38
+ assets/demo_atv.mp4 filter=lfs diff=lfs merge=lfs -text
39
+ assets/demo_car_motorway.mp4 filter=lfs diff=lfs merge=lfs -text
40
+ assets/demo_car_rural.mp4 filter=lfs diff=lfs merge=lfs -text
41
+ assets/demo_kart.mp4 filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -18,7 +18,7 @@ tags:
18
  - karting
19
  ---
20
 
21
- # SpeedNet v4 β€” ego-speed estimation from onboard video
22
 
23
  SpeedNet estimates **vehicle speed directly from onboard/POV video** β€” no GPS,
24
  no CAN bus, no sensors. Point it at a dashcam clip, a go-kart helmet-cam
@@ -29,11 +29,32 @@ footage that has none?* β€” e.g. indoor karting, where GPS does not work.
29
 
30
  ## Demo
31
 
32
- Fastest lap of an indoor go-kart race (1000 m track), with the speed HUD
33
- generated by this project β€” video-model level, IMU-driven dynamics, and the
34
- official lap time anchoring the scale:
 
 
35
 
36
- <video src="https://huggingface.co/x2q/speednet/resolve/main/assets/demo_bestlap.mp4" controls muted playsinline width="100%"></video>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
  ## Motivation
39
 
@@ -67,6 +88,16 @@ card because they will bite anyone building something similar:
67
  fusion described below: measured longitudinal g-force drives the
68
  acceleration profile, centripetal physics anchors cornering speed, and
69
  track length locks the scale.
 
 
 
 
 
 
 
 
 
 
70
 
71
  ```
72
  video ──► optical flow (motion field) ──┐
@@ -133,27 +164,28 @@ inference and 1-second median smoothing.
133
 
134
  ## Evaluation
135
 
136
- Held-out recordings (never trained on; the ATV test is from a different day
137
- than all ATV training data). RMSE in m/s, windowed protocol:
138
-
139
- | Test domain | RMSE (m/s) | Notes |
140
- |---|---|---|
141
- | ATV, forest trail (17 min, unseen day) | **0.65** | |
142
- | Car, highway 100–135 km/h (DK) | 5.60 | hardest regime |
143
- | Car, urban (DK) | 1.68 | |
144
- | Car, rural/urban Denmark (DJI, unseen recording) | 2.05 (zero-shot) | |
145
- | Car, EU driving-school fleet (L2D test split) | 2.70 | |
146
- | Car, US highway (comma2k19 test route) | 2.93 | |
147
- | Indoor go-kart, official lap times (holdout laps) | 5.2 km/h MAE (long-context mode) | 3.4 km/h with lap-aligned windows; vs. timing system, 1000 m track |
148
-
149
- The indoor go-kart figures are validated against the venue's race timing
150
- system: mean predicted speed per lap vs. `1000 m / official lap time`, on
151
- laps excluded from training. GPS-domain rows use short mode; the indoor row
152
- uses long-context mode (5.2 km/h), improving to 3.4 km/h when lap boundaries
153
- are known and inference windows are aligned to laps.
154
-
155
- ![Example: ATV test recording, prediction vs GPS](assets/example_atv.png)
156
- ![Example: indoor go-kart lap vs official timing](assets/example_indoor.png)
 
157
 
158
  ## Training data
159
 
@@ -161,7 +193,7 @@ are known and inference windows are aligned to laps.
161
 
162
  | Domain | Source | Speed signal |
163
  |---|---|---|
164
- | Indoor go-kart (2 races) | helmet cam, 1000 m indoor track | official lap times (weak supervision: mean speed per lap) |
165
  | ATV / forest | action cam + GPS remote | 10 Hz GPS |
166
  | Mini-loader / grass | action cam + GPS remote | 10 Hz GPS |
167
  | Car / Denmark | action cam + GPS, dashcam | 10 Hz + 1 Hz GPS |
@@ -176,8 +208,12 @@ photometric jitter on the context frame; per-recording train/val/test splits.
176
  ## Limitations
177
 
178
  - **Protocol sensitivity**: sequence length is a scale cue (an artifact of
179
- two-length training); use the mode matching your footage as described
180
- above. Removing this via length-randomized training is planned.
 
 
 
 
181
  - **Compressed dynamics within a lap/segment**: like most regression models,
182
  predictions are pulled toward the mean β€” cornering speeds read slightly
183
  high, straight-line peaks slightly low. If your footage has IMU data, see
 
18
  - karting
19
  ---
20
 
21
+ # SpeedNet v5 β€” ego-speed estimation from onboard video
22
 
23
  SpeedNet estimates **vehicle speed directly from onboard/POV video** β€” no GPS,
24
  no CAN bus, no sensors. Point it at a dashcam clip, a go-kart helmet-cam
 
29
 
30
  ## Demo
31
 
32
+ Four unedited minutes across the domains the model has to cope with. The
33
+ cyan trace is SpeedNet reading the video; the dashed white trace is GPS,
34
+ shown wherever ground truth exists, with a running MAE. Nothing is
35
+ cherry-picked β€” the two car clips are included precisely because open-road
36
+ driving is the model's weakest regime (see Limitations).
37
 
38
+ **ATV, forest trail** β€” 9–61 km/h, unseen recording. MAE **3.4 km/h**.
39
+
40
+ <video src="https://huggingface.co/x2q/speednet/resolve/main/assets/demo_atv.mp4" controls muted playsinline width="100%"></video>
41
+
42
+ **Car, country roads** β€” 19–64 km/h. MAE **11.1 km/h**.
43
+
44
+ <video src="https://huggingface.co/x2q/speednet/resolve/main/assets/demo_car_rural.mp4" controls muted playsinline width="100%"></video>
45
+
46
+ **Car, motorway** β€” 21–108 km/h. MAE **10.7 km/h**. High speed is a hard
47
+ case: at 110 km/h the flow field saturates and distant structure carries
48
+ most of the signal. See *Limitations*.
49
+
50
+ <video src="https://huggingface.co/x2q/speednet/resolve/main/assets/demo_car_motorway.mp4" controls muted playsinline width="100%"></video>
51
+
52
+ **Indoor kart** β€” no GPS exists here at all; this is the case the project was
53
+ built for. No ground-truth trace, because there is nothing to compare
54
+ against frame by frame; validation is against the venue's timing system
55
+ (see *Evaluation*).
56
+
57
+ <video src="https://huggingface.co/x2q/speednet/resolve/main/assets/demo_kart.mp4" controls muted playsinline width="100%"></video>
58
 
59
  ## Motivation
60
 
 
88
  fusion described below: measured longitudinal g-force drives the
89
  acceleration profile, centripetal physics anchors cornering speed, and
90
  track length locks the scale.
91
+ 6. **The published track length is not the driven distance.** Our indoor
92
+ supervision used `mean speed = track length / lap time` with the venue's
93
+ advertised 1000 m. That figure is the **centreline**. A racing line cuts
94
+ every corner by up to half the track width, so on a 13 m wide circuit
95
+ with 33.1 rad of total turning it saves `6.5 m x 33.1 = 215 m` β€” the
96
+ driven lap is ~790 m, and every label was 27% too fast. If you use
97
+ lap-time weak supervision, measure the turning and subtract; do not trust
98
+ the marketing number. Corner count is a good sanity check that you have
99
+ the right layout (we measured 14, matching the venue's spec) while being
100
+ completely independent of scale.
101
 
102
  ```
103
  video ──► optical flow (motion field) ──┐
 
164
 
165
  ## Evaluation
166
 
167
+ Held-out recordings, never trained on. Two inference modes exist (sequence
168
+ length acts as a scale cue for this architecture); both are reported β€”
169
+ pick per the recommendation column. RMSE in m/s against GPS:
170
+
171
+ | Test clip | short windows | streaming | recommended |
172
+ |---|---|---|---|
173
+ | ATV, forest trail (unseen day) | **0.99** | 1.60 | short |
174
+ | Car, coastal Denmark (zero-shot recording) | 1.57 | **1.39** | streaming |
175
+ | Car, low-speed urban | 4.44 | **4.25** | streaming |
176
+ | Car, urban/rural | 7.82 | **6.00** | streaming |
177
+ | Car, motorway 100–135 km/h | 6.50 | **5.87** | streaming |
178
+ | Indoor go-kart (lap means vs official timing) | β€” | **3.70 km/h MAE** (bias βˆ’2.84) | streaming |
179
+
180
+ The indoor row compares mean predicted speed per lap against
181
+ `driven lap length / official lap time` on laps excluded from training,
182
+ using the corrected 790 m driven-lap length (see challenge 6 above β€”
183
+ the venue's advertised 1000 m is the centreline).
184
+
185
+ **Scale caveat:** all speeds carry a Β±5% scale uncertainty indoors. The
186
+ 790 m driven-lap figure is bracketed by geometry (a racing line cannot be
187
+ shorter than ~785 m) and by flow evidence (which integrates to ~753 m);
188
+ the residual βˆ’2.8 km/h indoor bias reflects exactly this uncertainty.
189
 
190
  ## Training data
191
 
 
193
 
194
  | Domain | Source | Speed signal |
195
  |---|---|---|
196
+ | Indoor go-kart (2 races) | helmet cam, indoor kart circuit | official lap times (weak supervision: mean speed per lap over the 790 m driven racing line) |
197
  | ATV / forest | action cam + GPS remote | 10 Hz GPS |
198
  | Mini-loader / grass | action cam + GPS remote | 10 Hz GPS |
199
  | Car / Denmark | action cam + GPS, dashcam | 10 Hz + 1 Hz GPS |
 
208
  ## Limitations
209
 
210
  - **Protocol sensitivity**: sequence length is a scale cue (an artifact of
211
+ two-length training); use the recommended mode per the evaluation table
212
+ (short for trail/off-road, streaming for cars and closed courses).
213
+ Length-randomized training removes this β€” validated on a companion
214
+ track-specialized model β€” and is planned for the next release.
215
+ - **Indoor absolute scale is Β±5%**: supervision is lap time x driven lap
216
+ length, and the driven racing line length is derived, not surveyed.
217
  - **Compressed dynamics within a lap/segment**: like most regression models,
218
  predictions are pulled toward the mean β€” cornering speeds read slightly
219
  high, straight-line peaks slightly low. If your footage has IMU data, see
__pycache__/modeling_speednet.cpython-312.pyc CHANGED
Binary files a/__pycache__/modeling_speednet.cpython-312.pyc and b/__pycache__/modeling_speednet.cpython-312.pyc differ
 
assets/demo_atv.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:756a48eebfcf90fd72b34812c76fc5f1cea7f551f5883ffef7cfc235af882126
3
+ size 13116768
assets/demo_car_motorway.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:056566b4850eb9484579e377a1614f46a211274865a95e2c2537daaea7080095
3
+ size 2446651
assets/demo_car_rural.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:daaae976e706f37eccb3507f887dd8f82f31008f4a477ba4c026cf375dbc9eed
3
+ size 5543994
assets/demo_kart.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:982f6b0ccc36b57796187d08c4d203fd22bac05c67eecaa782fe8b3b4535b7ea
3
+ size 6110305
example.py CHANGED
@@ -18,7 +18,7 @@ video = sys.argv[1]
18
  device = "cuda" if torch.cuda.is_available() else "cpu"
19
 
20
  model = SpeedNet()
21
- model.load_state_dict(torch.load("speednet_v4.pt", map_location=device))
22
 
23
  r = predict_video(model, video, device=device)
24
 
 
18
  device = "cuda" if torch.cuda.is_available() else "cpu"
19
 
20
  model = SpeedNet()
21
+ model.load_state_dict(torch.load("speednet_v5.pt", map_location=device))
22
 
23
  r = predict_video(model, video, device=device)
24
 
modeling_speednet.py CHANGED
@@ -23,7 +23,7 @@ Typical usage
23
  import torch
24
 
25
  model = SpeedNet()
26
- model.load_state_dict(torch.load("speednet_v4.pt", map_location="cuda"))
27
  result = predict_video(model, "my_onboard_clip.mp4", device="cuda")
28
  # result["t"] -> timestamps in seconds
29
  # result["speed_mps"]-> speed in m/s (multiply by 3.6 for km/h)
 
23
  import torch
24
 
25
  model = SpeedNet()
26
+ model.load_state_dict(torch.load("speednet_v5.pt", map_location="cuda"))
27
  result = predict_video(model, "my_onboard_clip.mp4", device="cuda")
28
  # result["t"] -> timestamps in seconds
29
  # result["speed_mps"]-> speed in m/s (multiply by 3.6 for km/h)
speednet_v5.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8cad1e37d047ec4213c749494d7aee2957f706e89064d7d492b2cd6aa95981dc
3
+ size 3766617