TAC-UFLD v0.4.0 · elas_pilot_v2

TAC-UFLD: temporal lane detection pilots

Authors: Tiago Rodrigues, Eva Laussac, Everton Gomede · UTFPR, Cornélio Procópio, Brazil

Can a lightweight lane detector that looks at the previous frames beat the single-frame UFLD baseline? UFLD (ResNet-18) and a small CNN, each with temporal variants, trained on the ELAS ego-lane dataset and tested on three road scenes never used for training or model selection.

dataset ELAS11 models2 seedsheld-out scenes BR_S02 · VIX_S05 · VV_S03NVIDIA GeForce RTX 3050GPU time 4 h 47 minindicative pilot, not the full protocol

Where the research stands

Question: can a lightweight lane detector that also looks at the previous frames beat the single-frame UFLD baseline, and run on an in-car embedded system? Everything below comes from pilot runs on ELAS (2–3 seeds, short training, no hyper-parameter search), so it shows directions, not final claims.

Overfitting fixed0.07 → 0.86UFLD baseline, held-out lane F1: original augmentation vs + geometric augmentation (3 seeds)
Clean frames0.881 vs 0.895UFLD baseline vs the best temporal model (UFLD v0.7 ConvGRU): within seed noise (2 seeds)
Occluded current frame0.761 → 0.875UFLD baseline vs UFLD v0.3 gated when the current frame is occluded and the earlier frames are clean: +0.114, in every seed
Kalman tracker on the output−21 % jitterfor every model, with unchanged lane F1: the cheap temporal reference a learned model has to beat
Lightweight model0.850 · 2.8 MLite v0.5 lane F1 and parameters, against 0.881 with 21.8 M for the UFLD baseline (8× fewer parameters)

1 · Overfitting: what fixed it

0.00.20.40.60.81.0geometric0.858geometric flip0.769small head (256)0.210photometric extended0.150more scenes (18)0.129current-frame degradation0.094frozen stem + layer10.083none0.068photometric0.068backbone lr ×0.10.050regularised0.002
UFLD baseline trained with each recipe (same split, seeds and epochs); held-out lane F1. Geometric augmentation (shift, zoom, rotation, perspective) is the fix; flips and heavy regularisation are not.

2 · Where time helps: an occluded current frame

clean current frameoccluded current frame0.10.20.30.40.50.60.70.80.91.0UFLD baseline0.761 (-0.120)UFLD baseline +CT0.742 (-0.141)UFLD v0.2 weighted0.756 (-0.116)UFLD v0.3 gated0.875 (-0.008)UFLD v0.4 coord0.765 (-0.115)UFLD v0.6 aligned0.864 (-0.016)UFLD v0.7 ConvGRU0.802 (-0.093)Lite baseline0.254 (-0.069)Lite v0.5 warped0.829 (-0.021)Lite v0.5 static0.554 (-0.198)Lite v0.6 ConvGRU0.554 (-0.007)
Held-out lane F1 with clean frames (hollow) and with the current frame occluded by boxes while the earlier frames stay clean (filled); the number is the occluded F1 and its change. Single-frame models only see the damaged image.

3 · Accuracy against size

0.00.20.40.60.81.0UFLD baseline · 21.8 M0.881UFLD v0.2 weighted · 21.8 M0.872UFLD v0.3 gated · 21.9 M0.883UFLD v0.4 coord · 21.8 M0.880UFLD v0.6 aligned · 23.5 M0.880UFLD v0.7 ConvGRU · 22.1 M0.895Lite baseline · 2.5 M0.322Lite v0.5 warped · 2.8 M0.850Lite v0.5 static · 2.8 M0.752Lite v0.6 ConvGRU · 2.7 M0.561
Held-out lane F1 (clean frames) and parameters. Compute per frame: UFLD 7.1 GMAC, lite 2.0 GMAC; a temporal model streaming with cached features adds only its fusion (it recomputes 3 frames otherwise). Lite models from elas_lite_long (longer training).

4 · How far back to look (UFLD v0.4 coord)

-0.05-0.02+0.00+0.02+0.053 frames, step 2+0.0293 frames, step 5+0.0285 frames, step 5+0.0043 frames, step 10+0.027
Held-out lane F1 of UFLD v0.4 coord minus the UFLD baseline for each history length and spacing (history frame k = t − k·step; same split and baseline for every arm). Spacing changes little; five frames are worse than three.

Desafios

  • Base de dados pequena. O protocolo usa 10 cenas do ELAS, e só 3 ficam reservadas para teste. A UFLD decorava a posição das faixas até entrar o aumento de dados geométrico.
  • Quadros limpos escondem o efeito temporal. Com quadros limpos, os modelos temporais UFLD ficam a cerca de ±0,02 de lane F1 da baseline. Duas sementes não bastam para separar isso do ruído.
  • Os modelos leves treinam devagar e de forma instável. Treinados do zero, precisam de 16 épocas ou mais. O lite v0.5 sem histórico real (o controle de capacidade) marcou 0,877 em uma semente e 0,627 na outra. Com quadros limpos, ainda não se sabe quanto do ganho vem dos quadros anteriores; com o quadro atual ocluído, o histórico vale +0,17 e +0,38 nas duas sementes.
  • Memória em sequências longas. Os modelos recorrentes derivam quando o estado é mantido ao longo de uma cena inteira (lite v0.6: −0,48 de lane F1). Eles foram treinados só com clipes de 3 quadros.
  • Mais histórico não é melhor. Espaçar os quadros do histórico de 2, 5 ou 10 quadros não muda nada; usar 5 quadros em vez de 3 reduz o lane F1.
  • Uma única base de dados até agora. CULane, TuSimple e OpenLane ainda não foram baixadas. Os leitores estão prontos e foram testados em cópias sintéticas da estrutura delas.
  • Ainda sem medição embarcada. Os números da Jetson são simulações com fatores de lentidão assumidos, não medições.

Próximos passos

  1. Rodar o protocolo completo no ELAS: 6 sementes, até 50 épocas e o mesmo orçamento de busca de hiperparâmetros para todos os modelos (cerca de 4–5 dias na RTX 3050).
  2. Tornar a robustez um resultado principal: primeiro as corrupções sintéticas, depois oclusões naturais, noite e chuva.
  3. Baixar CULane e TuSimple (o guia de download está pronto), pré-treinar nelas, ajustar no ELAS e reportar as métricas oficiais delas.
  4. Resolver a questão dos modelos leves: mais sementes e treino mais longo para o lite v0.5 contra seu controle de capacidade, e treinar os modelos recorrentes com sequências longas.
  5. Última fase, embarcado: exportar o melhor modelo temporal leve para TensorRT (FP16/INT8) e medir latência, memória e consumo de energia em uma Jetson.

Challenges

  • Small dataset. The protocol uses 10 ELAS scenes, and only 3 are held out for testing. UFLD memorised lane positions until geometric augmentation was added.
  • Clean frames hide the temporal effect. On clean held-out frames the temporal UFLD models stay within about ±0.02 lane F1 of the baseline. Two seeds cannot separate that from noise.
  • The lightweight models train slowly and unstably. Trained from scratch, they need 16 epochs or more. Lite v0.5 without real history (the capacity control) scored 0.877 in one seed and 0.627 in the other. On clean frames it is still open how much of the gain comes from the earlier frames; with an occluded current frame, the history is worth +0.17 and +0.38 in both seeds.
  • Memory over long sequences. The recurrent models drift when their state is carried across a whole scene (lite v0.6: −0.48 lane F1). They were trained on 3-frame clips only.
  • More history is not better. Spacing the history frames 2, 5 or 10 frames apart changes nothing; 5 frames instead of 3 costs lane F1.
  • One dataset so far. CULane, TuSimple and OpenLane are not downloaded yet. Their readers are ready and were tested on synthetic copies of their layouts.
  • No embedded measurement yet. The Jetson numbers are simulations based on assumed slowdowns, not measurements.

Next steps

  1. Run the full protocol on ELAS: 6 seeds, up to 50 epochs, and the same hyper-parameter search budget for every model (about 4–5 days on the RTX 3050).
  2. Make robustness a primary result: the synthetic corruptions now, then natural occlusions, night and rain frames.
  3. Download CULane and TuSimple (the download guide is ready), pre-train on them, fine-tune on ELAS, and report their official metrics.
  4. Settle the lightweight question: more seeds and longer training for lite v0.5 against its capacity control, and train the recurrent models on long sequences.
  5. Last phase, embedded: export the best lightweight temporal model to TensorRT (FP16/INT8) and measure latency, memory and power on a Jetson.

Qual modelo comparar com a baselineWhich model to compare with the baseline

Lane F1 nas cenas de teste nunca vistas, média de 2 sementes; o quadro atual ocluído vem da avaliação de robustez (o histórico continua limpo). Resultados de piloto: indicam a direção, não provam.Lane F1 on the held-out scenes, mean of 2 seeds; the occluded current frame comes from the robustness evaluation (the history stays clean). Pilot results: they show the direction, they do not prove it.Modelos lite: execução elas_lite_long (treino mais longo).Lite models: run elas_lite_long (longer training).

SituaçãoSituationSupera a baseline?Better than the baseline?Melhor modeloBest modelNúmerosNumbers
Quadros limposClean framesNão claramenteNot clearlynenhum aindanone yetUFLD v0.7 ConvGRU: +0,014 (0,895 × 0,881); sem o histórico perde só 0,005, então o ganho não é temporalUFLD v0.7 ConvGRU: +0.014 (0.895 vs 0.881); without its history it loses only 0.005, so the gain is not temporal
Quadro atual ocluído (histórico limpo)Occluded current frame (clean history)Sim, em todas as sementesYes, in every seedUFLD v0.3 gatedUFLD v0.3 gatedUFLD v0.3 gated +0,114, UFLD v0.6 aligned +0,104, UFLD v0.7 ConvGRU +0,041 (baseline 0,761; controle com o mesmo treino 0,742)UFLD v0.3 gated +0.114, UFLD v0.6 aligned +0.104, UFLD v0.7 ConvGRU +0.041 (baseline 0.761; equal-training control 0.742)
Quadro atual borrado, escuro ou com ruídoBlurred, dark or noisy current frameNãoNonenhumnonetodas as diferenças entre -0,010 e +0,024every difference between -0.010 and +0.024
Cena de teste com oclusões reaisHeld-out scene with real occlusionsSim, mas é uma única cenaYes, but it is a single sceneUFLD v0.7 ConvGRUUFLD v0.7 ConvGRUUFLD v0.7 ConvGRU 0,791 × baseline 0,741; +CT 0,772UFLD v0.7 ConvGRU 0.791 vs baseline 0.741; +CT 0.772
Estabilidade (jitter)Smoothness (jitter)Não por um modelo aprendidoNot by a learned modelfiltro de Kalman na saídaKalman filter on the outputbaseline 1,51 px → 1,19 px com Kalman (−22 %); modelos temporais 1,45–1,75 pxbaseline 1.51 px → 1.19 px with Kalman (−22 %); temporal models 1.45–1.75 px
Modelo leve para embarcado (× UFLD baseline)Lightweight model for embedded use (vs UFLD baseline)Sob oclusão sim; em quadros limpos nãoUnder occlusion yes; on clean frames noLite v0.5 warpedLite v0.5 warpedlimpos -0,031, ocluídos +0,068, 8× menos parâmetros (2,8 M × 21,8 M); treinos diferentes: até 16 × 4 épocasclean -0.031, occluded +0.068, 8× fewer parameters (2.8 M vs 21.8 M); different training: up to 16 vs 4 epochs
O modelo leve usa o histórico? (× mesmas camadas sem histórico, com oclusão)Does the lite model use its history? (vs same layers without history, occluded)Sim, em todas as sementesYes, in every seedLite v0.5 warpedLite v0.5 warped0,829 × 0,554 (por semente +0,170 / +0,379)0.829 vs 0.554 (per seed +0.170 / +0.379)

Recomendação

  • Comparação principal: UFLD v0.3 (gated) × UFLD baseline. Mesma rede e mesmo treino, com praticamente nenhum parâmetro a mais; qualquer diferença vem do uso dos quadros anteriores. É o modelo que mais mantém as faixas quando o quadro atual está ocluído, e empata com a baseline em quadros limpos.
  • Comparação secundária, para o embarcado: lite v0.5 × UFLD baseline, e lite v0.5 × o mesmo modelo sem histórico. Mostra o custo de um modelo muito menor e, pelo controle sem histórico, que a robustez vem do tempo.
  • Declarar antes da execução completa. Esta escolha foi feita olhando o teste; para a afirmação ser válida, declare agora as comparações principais e a métrica com oclusão como métrica principal, e use as 6 sementes da execução completa para confirmar ou rejeitar.
  • Condição para comparar as famílias: treinar UFLD e lite com o mesmo protocolo (mesmas épocas máximas e busca de hiperparâmetros) antes de colocar os dois lado a lado num artigo.

Recommendation

  • Primary comparison: UFLD v0.3 (gated) vs the UFLD baseline. Same network and same training, with almost no extra parameters, so any difference comes from using the earlier frames. It is the model that keeps the lanes best when the current frame is occluded, and it ties the baseline on clean frames.
  • Secondary comparison, for the embedded goal: lite v0.5 vs the UFLD baseline, and lite v0.5 vs the same model without history. It shows the cost of a much smaller model and, through the no-history control, that the robustness comes from time.
  • Declare before the full run. This choice was made by looking at the test set. For the claim to hold, declare the primary comparisons now, with occluded-frame F1 as a primary metric, and let the 6 seeds of the full run confirm or reject them.
  • Condition for comparing the families: train UFLD and lite under the same protocol (same maximum epochs and hyper-parameter search) before putting them side by side in a paper.

Os candidatos lado a ladoThe candidates side by side

ModeloModelF1 limposClean F1F1 ocluídosOccluded F1Δ oclusão × baselineΔ occluded vs baselineParâmetros (M)Parameters (M)Perda sem históricoCost without historyNotaNote
UFLD baseline0.8810.761—21.8—referência de um quadrosingle-frame reference
UFLD baseline +CT0.8830.742-0.01821.8—controle: o mesmo treino extra dos modelos temporais, sem históricocontrol: the temporal models' extra training, without history
UFLD v0.2 weighted0.8720.756-0.00521.80.001sem ganho com oclusãono gain under occlusion
UFLD v0.3 gated0.8830.875+0.11421.90.012recomendado: robusto à oclusão, quase sem custo extrarecommended: robust to occlusion, almost no extra cost
UFLD v0.4 coord0.8800.765+0.00421.80.003sem ganho com oclusão; escolhido na validação limpa para a ablação de históricono gain under occlusion; chosen on clean validation for the history ablation
UFLD v0.6 aligned0.8800.864+0.10423.50.008quase tão robusto quanto a v0.3, porém maior e mais complexonearly as robust as v0.3, but larger and more complex
UFLD v0.7 ConvGRU0.8950.802+0.04122.10.005melhor em quadros limpos, mas o ganho não é temporal; o estado deriva em sequências longasbest on clean frames, but the gain is not temporal; its state drifts over long sequences
Lite baseline0.3220.254-0.5072.5—referência leve de um quadrolightweight single-frame reference
Lite baseline +CT0.3220.258-0.5032.5—controle de treino da família litetraining control of the lite family
Lite v0.5 warped0.8500.829+0.0682.80.004candidato embarcado: usa o histórico sob oclusãoembedded candidate: uses its history under occlusion
Lite v0.5 static0.7520.554-0.2062.8—controle de capacidade: mesmas camadas, sem histórico; instávelcapacity control: same layers, no history; unstable
Lite v0.6 ConvGRU0.5610.554-0.2062.70.009recorrente leve; ainda fracolightweight recurrent; still weak

“Perda sem histórico”: quanto o lane F1 cai quando o histórico é trocado pelo quadro atual no teste (quadros limpos).“Cost without history”: how much lane F1 drops when the history is replaced by the current frame at test time (clean frames).

O que os resultados mostram

  • O aumento de dados geométrico elimina o overfitting da UFLD. Na ablação de aumento de dados (UFLD baseline, 3 sementes, mesma divisão e mesmo orçamento), pequenos deslocamentos, zooms, rotações e mudanças de perspectiva aleatórios, aplicados ao clipe inteiro, elevam o melhor lane F1 de validação de 0,161 para 0,772 e o lane F1 nas cenas de teste nunca vistas de 0,068 para 0,858. A melhor época passa da 1 para a 4, a última. Só as mudanças fotométricas chegam a 0,150 no teste; o espelhamento não acrescenta nada (0,769). A receita do segundo piloto foi escolhida na validação: aumento geométrico mais degradação do quadro atual, para todos os modelos.
  • Dropout + label smoothing + weight decay juntos pioram a UFLD (0,002 no teste). As faixas continuam sendo previstas em todos os quadros, mas no lugar errado. A causa provável é o label smoothing: ele achata a distribuição sobre as 100 células da grade e puxa o soft-argmax para o centro da imagem. Como o braço muda três coisas ao mesmo tempo, isto é uma hipótese.
  • Nenhum outro remédio isolado resolve o overfitting. Outros cinco braços da mesma ablação mudam uma única coisa na receita original (3 sementes): taxa de aprendizado do backbone 10× menor (lane F1 no teste 0,050), stem e primeiro estágio da ResNet congelados (0,083), degradação do quadro atual (0,094), oito cenas de treino a mais (0,129) e uma cabeça de 256 unidades em vez de 2048 (0,211). Todos continuam com o melhor resultado na época 1 ou 2. Só o aumento de dados geométrico (0,858) elimina o problema, e por isso ele continua sendo a receita de todos os modelos.
  • Com a nova receita, a UFLD baseline chega a 0,881 de lane F1 no teste (0,849 nas cenas já vistas), contra 0,057 no primeiro piloto. O segundo piloto treinou 11 modelos × 2 sementes em 4 h 47 min na RTX 3050.
  • Os modelos temporais UFLD empatam com a baseline, mas não a superam com clareza. A v0.2, a v0.3, a v0.4 e a v0.6 ficam entre 0,872 e 0,883; o controle com o mesmo treino extra fica em 0,883. A UFLD v0.7 (ConvGRU) é a mais alta, com 0,895 (+0,014 sobre a baseline, +0,012 sobre o controle). Porém, trocar o histórico dela pelo quadro atual no teste custa só 0,005, então esse ganho não é claramente temporal.
  • Os modelos lite ficam subtreinados após 4 épocas da nova receita (eles treinam do zero): lite baseline 0,218, +CT 0,312. O lite v0.5 chega a 0,700 e o lite v0.6 a 0,541, bem acima de ambos, mas trocar o histórico pelo quadro atual custa só 0,020 e 0,017. A maior parte da vantagem vem, portanto, das camadas extras de fusão, e não do tempo.
  • Com 16 épocas, a família lite se aproxima da UFLD com 8× menos parâmetros. A execução lite mais longa (elas_lite_long, 2 sementes, parada antecipada) leva o lite v0.5 a 0,850 de lane F1 no teste (0,844 / 0,856) com 2,8 M de parâmetros, contra 0,881 da UFLD baseline com 21,8 M. O lite baseline fica em 0,322, e mais treino não o ajuda (+CT 0,322). O controle de capacidade (lite v0.5 com o quadro atual em todas as posições, as mesmas camadas) é instável: 0,877 na semente 1 e 0,627 na semente 2. Por isso, com quadros limpos, quanto do ganho do lite v0.5 vem dos quadros anteriores ainda está em aberto (+0,098 em média; −0,033 e +0,229 por semente). O lite v0.6 (ConvGRU) chega a 0,561.
  • O filtro de Kalman dá a suavidade de graça. Em todos os modelos, ele reduz o jitter (a oscilação da posição prevista entre quadros) em cerca de 20 % (UFLD baseline: de 1,51 para 1,19 px) sem alterar o lane F1. Os modelos temporais UFLD aprendidos oscilam tanto quanto a baseline (1,45 a 1,75 px contra 1,51 px); portanto, é o filtro, e não a fusão, que deixa a saída mais suave.
  • Manter o estado recorrente ao longo de uma cena inteira ainda não funciona. Treinada com clipes de 3 quadros, a ConvGRU deriva quando o estado nunca é reiniciado: a UFLD v0.7 perde 0,028 e o lite v0.6 perde 0,483 de lane F1 nesse modo. Para usar um único estado contínuo no carro, é preciso antes treinar com sequências longas (retropropagação truncada no tempo).
  • A oclusão é onde o tempo pode ajudar. Na única cena de teste marcada como "oclusão" (VIX_S05), a UFLD v0.7 marca 0,792, contra 0,741 da baseline e 0,772 do controle com o mesmo treino extra; nas outras duas cenas a baseline é a melhor (0,948). Uma única cena é anedótica.
  • Quando o quadro atual está ocluído, os modelos temporais mantêm as faixas. A avaliação de robustez (python -m tac_ufld robustness) reavaliou todos os checkpoints nos 2.610 quadros de teste. Em cada quadro, a imagem atual foi coberta por retângulos, borrada, escurecida ou recebeu ruído, enquanto os quadros do histórico ficaram limpos; todos os modelos viram as mesmas corrupções. Com oclusão (673 quadros), a UFLD v0.3 mantém 0,875 de lane F1 (sementes 0,865 / 0,886) e a v0.6 0,864 (0,857 / 0,871), contra 0,761 da baseline (0,753 / 0,768) e 0,742 do controle com o mesmo treino extra. São +0,11 nas duas sementes; mais treino, sozinho, não fecha a diferença. Em todos os quadros degradados, a v0.3 chega a 0,886 e a v0.6 a 0,884, contra 0,850 da baseline; para a v0.3 e a v0.6, isso fica levemente acima do F1 com quadros limpos (0,883 e 0,880). Desfoque, escurecimento e ruído quase não afetam nenhum modelo UFLD (dentro de ±0,03). A v0.7 ganha menos com oclusão (0,802), e os modelos lite perdem de 0,02 a 0,07, como suas baselines. O filtro de Kalman não acrescenta nada aqui. Ressalvas: 2 sementes, um único conjunto fixo de corrupções sintéticas, e os modelos foram treinados com degradação do quadro atual; então isto mede o que esse treino ensina, e não oclusões naturais.
  • Com o quadro atual ocluído, o modelo lite claramente usa o histórico. Na avaliação de robustez da execução lite longa, o lite v0.5 mantém 0,829 de lane F1 com oclusão (sementes 0,817 / 0,840, só 0,02 abaixo do valor com quadros limpos). O controle de capacidade, com as mesmas camadas mas o quadro atual em todas as posições, cai para 0,554 (0,648 / 0,461). São +0,17 e +0,38 a favor do histórico real, nas duas sementes. O lite baseline fica perto de 0,25 e o lite v0.6 perto de 0,55. Mesmas ressalvas da UFLD: 2 sementes, oclusões sintéticas.
  • Olhar mais para trás não ajuda; olhar mais quadros atrapalha. A ablação de histórico (ablation_history, UFLD v0.4, o modelo temporal escolhido na validação do piloto 2, 2 sementes) usa sua própria divisão, com blocos de 180 quadros, na qual a baseline marca 0,831. A v0.4 ganha +0,029 sobre a baseline com 3 quadros espaçados de 2, +0,028 espaçados de 5 e +0,027 espaçados de 10, mas só +0,004 com 5 quadros espaçados de 5. O espaçamento do histórico quase não importa nessa faixa; uma janela mais longa piora a v0.4.
  • Custo. Com as features do histórico em cache, cada modelo temporal UFLD custa o mesmo que sua baseline (7,1 GMACs por quadro) mais a fusão. Por clipe de 3 quadros, a v0.7 precisa de 21,5 GMACs e 22,1 M de parâmetros (+0,3 M), e a v0.6 de 21,8 GMACs e 23,5 M (+1,7 M). Os modelos lite precisam de 2,0 GMACs por quadro e de 2,5 a 2,8 M de parâmetros.

What the results show

  • Geometric augmentation removes the UFLD overfitting. In the augmentation ablation (UFLD baseline, 3 seeds, same split and budget), small random shifts, zooms, rotations and perspective changes applied to the whole clip lift the best validation lane F1 from 0.161 to 0.772 and the held-out lane F1 from 0.068 to 0.858. The best epoch moves from 1 to 4, the last one. Photometric changes alone reach 0.150 held-out; flips add nothing (0.769). The recipe of the second pilot was chosen on validation: geometric augmentation plus current-frame degradation, for every model.
  • Dropout + label smoothing + weight decay together make UFLD worse (held-out 0.002). Lanes are still predicted in every frame but misplaced. The likely cause is label smoothing, which flattens the distribution over the 100 grid cells and pulls the soft-argmax towards the image centre; the arm changes three things at once, so this is a hypothesis.
  • No other single remedy fixes the overfitting. Five more arms of the same ablation change one thing each in the original recipe (3 seeds): a 10x lower backbone learning rate (held-out lane F1 0.050), frozen stem and first ResNet stage (0.083), current-frame degradation (0.094), eight more training scenes (0.129) and a 256-unit head instead of 2048 (0.211). Every one still peaks at epoch 1 or 2. Only geometric augmentation (0.858) removes the problem, so it remains the recipe for every model.
  • With the new recipe the UFLD baseline reaches 0.881 held-out lane F1 (0.849 on seen scenes), against 0.057 in the first pilot. The second pilot trained 11 models × 2 seeds in 4 h 47 min on the RTX 3050.
  • The UFLD temporal models match the baseline but do not clearly beat it. v0.2, v0.3, v0.4 and v0.6 land between 0.872 and 0.883, the equal-training control at 0.883. UFLD v0.7 (ConvGRU) is highest at 0.895 (+0.014 over the baseline, +0.012 over the control), but replacing its history by the current frame at test time costs only 0.005, so that gain is not clearly temporal.
  • The lite models are under-trained after 4 epochs of the new recipe (they train from scratch): lite baseline 0.218, +CT 0.312. Lite v0.5 reaches 0.700 and lite v0.6 0.541, far above both, but replacing their history by the current frame costs only 0.020 and 0.017. Most of their lead therefore comes from the extra fusion layers, not from time.
  • With 16 epochs the lite family comes close to UFLD, with 8× fewer parameters. The longer lite run (elas_lite_long, 2 seeds, early stopping) puts lite v0.5 at 0.850 held-out lane F1 (0.844 / 0.856) with 2.8 M parameters, against 0.881 for the UFLD baseline with 21.8 M. The lite baseline stays at 0.322 and more training does not help it (+CT 0.322). The capacity control (lite v0.5 with the current frame in every position, the same layers) is unstable: 0.877 in seed 1 and 0.627 in seed 2. On clean frames, the share of lite v0.5's gain that comes from the earlier frames is therefore still open (+0.098 on average, −0.033 and +0.229 per seed). Lite v0.6 (ConvGRU) reaches 0.561.
  • The Kalman tracker gives the smoothness for free. On every model it lowers jitter by about 20 % (UFLD baseline 1.51 to 1.19 px) with unchanged lane F1. The learned temporal UFLD models are about as steady as their baseline (1.45 to 1.75 px against 1.51 px), so the tracker, not the fusion, is what makes the output smoother.
  • Carrying the recurrent state over a whole scene does not work yet. Trained on 3-frame clips, the ConvGRU drifts when its state is never reset: UFLD v0.7 loses 0.028 and lite v0.6 0.483 lane F1 in carry mode. One-state deployment needs training on long sequences (truncated back-propagation through time) first.
  • Occlusion is where time might help. In the one held-out scene tagged "occlusion" (VIX_S05), UFLD v0.7 scores 0.792 against 0.741 for the baseline and 0.772 for the equal-training control; in the other two scenes the baseline is best (0.948). One scene is anecdotal.
  • When the current frame is occluded, the temporal models keep the lanes. The robustness evaluation (python -m tac_ufld robustness) re-ran every checkpoint on the 2,610 held-out frames. In each frame the current image was occluded by boxes, blurred, darkened or made noisy, while the history frames stayed clean; every model saw the same corruptions. Under occlusion (673 frames), UFLD v0.3 keeps 0.875 lane F1 (seeds 0.865 / 0.886) and v0.6 0.864 (0.857 / 0.871), against 0.761 for the baseline (0.753 / 0.768) and 0.742 for the equal-training control. That is +0.11 in both seeds, so more training alone does not close the gap. Over all degraded frames, v0.3 reaches 0.886 and v0.6 0.884 against 0.850 for the baseline. For v0.3 and v0.6 that is marginally above their clean-frame F1 (0.883 and 0.880). Blur, darkening and noise barely hurt any UFLD model (within ±0.03). v0.7 gains less under occlusion (0.802), and the lite models lose 0.02–0.07 like their baselines. The Kalman tracker adds nothing here. Caveats: 2 seeds, one fixed set of synthetic corruptions, and the models were trained with current-frame degradation, so this measures what that training teaches, not natural occlusions.
  • With an occluded current frame, the lite model clearly uses its history. In the robustness evaluation of the longer lite run, lite v0.5 keeps 0.829 lane F1 under occlusion (seeds 0.817 / 0.840, only 0.02 below clean). The capacity control, with the same layers but the current frame in every position, falls to 0.554 (0.648 / 0.461). That is +0.17 and +0.38 for the real history, in both seeds. The lite baseline stays near 0.25 and lite v0.6 near 0.55. Same caveats as for UFLD: 2 seeds, synthetic occlusions.
  • Looking further back does not help; looking at more frames hurts. The history ablation (ablation_history, UFLD v0.4, the temporal model chosen on pilot-2 validation, 2 seeds) uses its own split with 180-frame blocks, where the baseline scores 0.831. It gains +0.029 over the baseline with 3 frames 2 apart, +0.028 with 5 apart and +0.027 with 10 apart, but only +0.004 with 5 frames 5 apart. The spacing of the history barely matters in this range; a longer window makes v0.4 worse.
  • Cost. With cached history features each temporal UFLD model costs its baseline (7.1 GMACs per frame) plus the fusion; per 3-frame clip v0.7 needs 21.5 GMACs and 22.1 M parameters (+0.3 M), v0.6 21.8 GMACs and 23.5 M (+1.7 M). The lite models need 2.0 GMACs per frame and 2.5 to 2.8 M parameters.

The models

Two families, each a single-frame baseline and temporal variants built on it. All of them read the current frame and predict the two ego lanes of that frame; the temporal ones also read earlier frames.

t - 4t - 2t (current)camera frames (step 2)Backbonesame weightsfor every frameResNet-18 (UFLD)4-block CNN (lite)past frames: cached featuresTemporal fusionwhere the models differnonebaselines, +CTweighted sumv0.2, v0.4per-cell gatesv0.3warp + gatev0.5, v0.6ConvGRUv0.7, lite v0.6Row-anchorhead18 rows x 100cells per lanelanes(+ Kalman)
  • Every temporal model keeps its baseline's backbone and head and only adds a fusion step between them. It is compared with its own baseline on the same seeds.
  • Three questions separate the temporal models: do they align the frames before fusing (v0.5, v0.6), how do they remember (a fixed 3-frame window for v0.2 to v0.6, a recurrent state for v0.7 and lite v0.6), and what do they cost (UFLD about 7 GMACs per frame, lite about 2).
  • With feature caching each frame is encoded once, so a temporal model costs its baseline plus the fusion step, not three backbones.
  • The controls are not candidates. +CT separates a temporal gain from extra training, lite v0.5 static separates it from the extra fusion layers, and the Kalman tracker shows what simple output filtering already gives.
ModelRoleFrames usedHow history entersAligns motionMemoryParams (M)
UFLD family (ResNet-18, ImageNet)
UFLD baselinebaselinetnonenonone21.78
UFLD baseline +CTcontroltnonenonone21.78
UFLD v0.2 weightedtemporalt-4, t-2, tweighted averageno3-frame window21.78
UFLD v0.3 gatedtemporalt-4, t-2, tper-cell gatesno3-frame window21.91
UFLD v0.4 coordtemporalt-4, t-2, tweighted averageno3-frame window21.78
UFLD v0.6 alignedtemporalt-4, t-2, twarp + gateyes (learned flow)3-frame window23.50
UFLD v0.7 ConvGRUtemporalt-4, t-2, tConvGRUnorecurrent state22.07
Lite family (4-block CNN, from scratch)
Lite baselinebaselinetnonenonone2.49
Lite baseline +CTcontroltnonenonone2.49
Lite v0.5 warpedtemporalt-4, t-2, twarp + gateyes (learned flow)3-frame window2.84
Lite v0.6 ConvGRUtemporalt-4, t-2, tConvGRUnorecurrent state2.73
UFLD family

UFLD baseline

baselineOfficial UFLD (Qin et al., ECCV 2020), supervisor's notebook21.78 M params · 7.1 GMACs per clip

What it doesUltra-Fast Lane Detection with an ImageNet-pretrained ResNet-18. Lane detection is row-wise classification: for each of 18 image rows and each lane slot the head picks one of 100 horizontal cells, or "no lane". One frame in, no memory.

DifferenceThe reference of the UFLD family. Every UFLD temporal model starts from its trained weights and is compared with it on the same seeds.

UFLD baseline +CT

controlv0.4 control21.78 M params · 7.1 GMACs per clip

What it doesThe same network trained a second time from its own best checkpoint, with exactly the schedule the temporal variants get after their warm start.

DifferenceA control, not a candidate. A temporal model that beats the baseline but not this control gained from extra training, not from time.

UFLD v0.2 weighted

temporalSupervisor's notebook21.78 M params · 21.3 GMACs per clip, 3 frames per clip

What it doesEncodes the three frames with the shared ResNet and averages the feature maps with three learned weights (starting at 0.1 / 0.2 / 0.7) before the UFLD head. Trained with an extra existence loss and a temporal-consistency loss.

DifferenceThe simplest fusion: one weight per frame, the same at every pixel. Lane markings that moved between frames are averaged at different positions.

UFLD v0.3 gated

temporalSupervisor's notebook21.91 M params · 21.4 GMACs per clip, 3 frames per clip

What it doesLike v0.2, but a small convolutional network predicts a softmax gate per frame and per feature cell, biased towards the current frame.

DifferenceCan use history only where the current frame is weak, such as an occluded cell. Like v0.2 it fuses feature maps that are not aligned.

UFLD v0.4 coord

temporalSupervisor's notebook21.78 M params · 21.3 GMACs per clip, 3 frames per clip

What it doesv0.2's network with a different loss: a soft-argmax coordinate term penalises the lane position error in pixels, and the existence loss is re-weighted.

DifferenceSame fusion as v0.2. It tests whether a position-aware loss helps; the network itself is unchanged.

UFLD v0.6 aligned

temporalNew in v0.4 (port of lite v0.5)23.50 M params · 21.8 GMACs per clip, 3 frames per clip

What it doesA learned flow field (up to 4 cells of the 12x16 feature grid, about 128 px) warps each history map onto the current frame. The aligned history is compressed and blended in through a per-cell gate that starts almost closed.

DifferenceThe only UFLD model that aligns frames before fusing, so moving markings are not blurred. It adds about 1.7 M parameters to the baseline.

UFLD v0.7 ConvGRU

temporalNew in v0.422.07 M params · 21.5 GMACs per clip, 3 frames per clip

What it doesA convolutional GRU (64 channels) runs over the reduced feature maps from the oldest frame to the current one. Its final state is projected back and added to the current features. The projection starts at zero, so the untrained model is exactly the baseline.

DifferenceRemembers through a gated recurrence instead of a weighted sum. A deployment can carry one hidden state per camera instead of storing past feature maps.

Lite family

Lite baseline

baselineELAS development script2.49 M params · 2.0 GMACs per clip

What it doesA small CNN: four stride-2 convolution blocks (32 to 128 channels) and a head that pools the features to the 18x100 row-anchor grid and classifies every row with a shared MLP. Trained from scratch, without ImageNet.

DifferenceThe reference of the lite family: about 8 times fewer parameters and 3 to 4 times less compute than UFLD.

Lite baseline +CT

controlv0.4 control2.49 M params · 2.0 GMACs per clip

What it doesThe lite baseline trained a second time from its own best checkpoint with the temporal variants' schedule.

DifferenceThe equal-training control for lite v0.5 and lite v0.6.

Lite v0.5 warped

temporalELAS development script (refactored)2.84 M params · 6.0 GMACs per clip, 3 frames per clip

What it doesThe lite baseline plus warped residual fusion: a learned flow (up to 8 cells at stride 16, about 128 px) aligns each history feature map to the current one, and a per-pixel gate that starts closed mixes the aligned history in.

DifferenceSame fusion idea as UFLD v0.6 on a network that is 8 times smaller.

Lite v0.6 ConvGRU

temporalNew in v0.42.73 M params · 6.1 GMACs per clip, 3 frames per clip

What it doesThe lite baseline plus the ConvGRU fusion of UFLD v0.7 (64 hidden channels, read-out starting at zero).

DifferenceRecurrent memory on the smallest network: the candidate for an embedded system that keeps one state tensor per camera. Unlike v0.5 it does not align frames explicitly.

Reference, not a model: Any model + Kalman tracker: a causal constant-velocity Kalman filter on every lane point, with existence smoothing, tuned on validation. It costs microseconds per frame and is the bar a learned temporal model has to clear.

Lane F1 on unseen roads

CULane-style lane F1: each lane drawn 12 px wide (30 px at 1640 px, scaled to 640 px), matched one-to-one, correct when IoU ≥ 0.5. Post-processing tuned on validation only. On ELAS every model predicts both ego lanes in every frame, so precision = recall = F1: the errors are misplaced lanes, not missed ones.

Held-out test scenes (unseen roads)

0.00.20.40.60.81.0UFLD baseline0.881UFLD baseline +CT0.883UFLD v0.2 weighted0.872UFLD v0.3 gated0.883UFLD v0.4 coord0.880UFLD v0.6 aligned0.880UFLD v0.7 ConvGRU0.895Lite baseline0.218Lite baseline +CT0.312Lite v0.5 warped0.700Lite v0.6 ConvGRU0.541

Seen-scene test blocks

0.00.20.40.60.81.0UFLD baseline0.849UFLD baseline +CT0.847UFLD v0.2 weighted0.845UFLD v0.3 gated0.855UFLD v0.4 coord0.841UFLD v0.6 aligned0.850UFLD v0.7 ConvGRU0.851Lite baseline0.169Lite baseline +CT0.389Lite v0.5 warped0.793Lite v0.6 ConvGRU0.685
UFLD familyLite familybars = mean over seeds, dots = individual seeds

Held-out test scenes, all metrics (mean ± std over seeds)

ModelLane F1 @0.5Lane F1 @0.35Pixel F1Anchor F1Jitter pxFPFN
UFLD baseline0.881 ± 0.0010.962 ± 0.0080.812 ± 0.0040.951 ± 0.0011.51 ± 0.01622 ± 4622 ± 4
UFLD baseline +CT0.883 ± 0.0050.963 ± 0.0040.809 ± 0.0010.949 ± 0.0011.81 ± 0.00610 ± 27610 ± 27
UFLD v0.2 weighted0.872 ± 0.0070.954 ± 0.0100.806 ± 0.0070.948 ± 0.0031.45 ± 0.02670 ± 37670 ± 37
UFLD v0.3 gated0.883 ± 0.0150.958 ± 0.0050.814 ± 0.0080.950 ± 0.0011.58 ± 0.04608 ± 77608 ± 77
UFLD v0.4 coord0.880 ± 0.0230.954 ± 0.0140.808 ± 0.0120.949 ± 0.0041.48 ± 0.15626 ± 122626 ± 122
UFLD v0.6 aligned0.880 ± 0.0110.957 ± 0.0110.811 ± 0.0090.949 ± 0.0051.75 ± 0.11626 ± 59626 ± 59
UFLD v0.7 ConvGRU0.895 ± 0.0140.961 ± 0.0110.816 ± 0.0080.951 ± 0.0041.63 ± 0.11549 ± 75549 ± 75
Lite baseline0.218 ± 0.0100.370 ± 0.0000.408 ± 0.0080.566 ± 0.0191.77 ± 0.214078 ± 544078 ± 54
Lite baseline +CT0.312 ± 0.0610.482 ± 0.0570.483 ± 0.0560.663 ± 0.0422.68 ± 0.123586 ± 3173586 ± 317
Lite v0.5 warped0.700 ± 0.0120.899 ± 0.0030.722 ± 0.0000.903 ± 0.0161.83 ± 0.041562 ± 621562 ± 62
Lite v0.6 ConvGRU0.541 ± 0.0110.754 ± 0.0090.648 ± 0.0020.814 ± 0.0122.00 ± 0.012394 ± 562394 ± 56

Seen-scene test

ModelLane F1 @0.5Lane F1 @0.35Pixel F1Anchor F1Jitter pxFPFN
UFLD baseline0.849 ± 0.0010.896 ± 0.0130.807 ± 0.0030.933 ± 0.0052.01 ± 0.01190 ± 1190 ± 1
UFLD baseline +CT0.847 ± 0.0020.904 ± 0.0030.810 ± 0.0010.936 ± 0.0002.36 ± 0.05192 ± 3192 ± 3
UFLD v0.2 weighted0.845 ± 0.0050.896 ± 0.0050.810 ± 0.0050.932 ± 0.0051.88 ± 0.16195 ± 6195 ± 6
UFLD v0.3 gated0.855 ± 0.0070.902 ± 0.0080.817 ± 0.0080.935 ± 0.0052.08 ± 0.07182 ± 9182 ± 9
UFLD v0.4 coord0.841 ± 0.0230.900 ± 0.0150.810 ± 0.0150.929 ± 0.0081.93 ± 0.03200 ± 28200 ± 29
UFLD v0.6 aligned0.850 ± 0.0030.898 ± 0.0030.814 ± 0.0050.931 ± 0.0032.40 ± 0.28187 ± 4189 ± 4
UFLD v0.7 ConvGRU0.851 ± 0.0020.899 ± 0.0080.815 ± 0.0080.934 ± 0.0022.14 ± 0.19188 ± 2188 ± 2
Lite baseline0.169 ± 0.0140.438 ± 0.0280.451 ± 0.0120.648 ± 0.0001.83 ± 0.291044 ± 171044 ± 17
Lite baseline +CT0.389 ± 0.0280.615 ± 0.0040.567 ± 0.0050.741 ± 0.0102.61 ± 0.09768 ± 35768 ± 35
Lite v0.5 warped0.793 ± 0.0120.858 ± 0.0040.738 ± 0.0110.906 ± 0.0032.07 ± 0.30260 ± 16260 ± 16
Lite v0.6 ConvGRU0.685 ± 0.0030.801 ± 0.0210.694 ± 0.0020.865 ± 0.0032.02 ± 0.00396 ± 4396 ± 4

Does temporal context help?

Each temporal model is compared with the single-frame model of its own family on the same seeds (exact Wilcoxon, Holm correction). With 2 seeds no difference can reach p < 0.05 unless there are at least 6 seeds, so the verdicts here are indicative.

Temporal model minus its single-frame baseline (held-out lane F1)

-0.57-0.29+0.00+0.29+0.57UFLD v0.2 weighted − UFLD baseline-0.009UFLD v0.3 gated − UFLD baseline+0.003UFLD v0.4 coord − UFLD baseline-0.001UFLD v0.6 aligned − UFLD baseline-0.001UFLD v0.7 ConvGRU − UFLD baseline+0.014Lite v0.5 warped − Lite baseline+0.483Lite v0.6 ConvGRU − Lite baseline+0.323
Temporal modelCompared withSeedsΔ lane F195 % CIWilcoxon pHolm pVerdict
UFLD v0.2 weightedUFLD baseline2-0.009[-0.081, +0.063]0.5001.000underpowered
UFLD v0.3 gatedUFLD baseline2+0.003[-0.138, +0.143]1.0001.000underpowered
UFLD v0.4 coordUFLD baseline2-0.001[-0.218, +0.216]1.0001.000underpowered
UFLD v0.6 alignedUFLD baseline2-0.001[-0.110, +0.109]1.0001.000underpowered
UFLD v0.7 ConvGRUUFLD baseline2+0.014[-0.123, +0.151]0.5001.000underpowered
Lite v0.5 warpedLite baseline2+0.483[+0.283, +0.683]0.5001.000underpowered
Lite v0.6 ConvGRULite baseline2+0.323[+0.133, +0.513]0.5001.000underpowered

Equal-training control

Temporal models start from their baseline's best checkpoint and train further. The +CT baseline gets the same extra training; a temporal gain that survives this comparison is not an effect of more epochs.

-0.51-0.25+0.00+0.25+0.51UFLD v0.2 weighted − UFLD baseline +CT-0.011UFLD v0.3 gated − UFLD baseline +CT+0.000UFLD v0.4 coord − UFLD baseline +CT-0.003UFLD v0.6 aligned − UFLD baseline +CT-0.003UFLD v0.7 ConvGRU − UFLD baseline +CT+0.012Lite v0.5 warped − Lite baseline +CT+0.388Lite v0.6 ConvGRU − Lite baseline +CT+0.229UFLD baseline +CT − UFLD baseline+0.002Lite baseline +CT − Lite baseline+0.094
ModelCompared withSeedsΔ lane F195 % CIWilcoxon pHolm pVerdict
UFLD v0.2 weightedUFLD baseline +CT2-0.011[-0.030, +0.007]0.5001.000underpowered
UFLD v0.3 gatedUFLD baseline +CT2+0.000[-0.086, +0.087]1.0001.000underpowered
UFLD v0.4 coordUFLD baseline +CT2-0.003[-0.166, +0.160]1.0001.000underpowered
UFLD v0.6 alignedUFLD baseline +CT2-0.003[-0.059, +0.053]1.0001.000underpowered
UFLD v0.7 ConvGRUUFLD baseline +CT2+0.012[-0.071, +0.095]0.5001.000underpowered
Lite v0.5 warpedLite baseline +CT2+0.388[-0.265, +1.042]0.5001.000underpowered
Lite v0.6 ConvGRULite baseline +CT2+0.229[-0.415, +0.872]0.5001.000underpowered
UFLD baseline +CTUFLD baseline2+0.002[-0.051, +0.056]1.0001.000underpowered
Lite baseline +CTLite baseline2+0.094[-0.359, +0.548]0.5001.000underpowered

Against the Kalman tracker

The same predictions filtered by the output Kalman tracker (tuned on validation). This is what time gives almost for free; a learned temporal model should beat its baseline + Kalman (paired table below).

ModelLane F1Lane F1 + KalmanJitter pxJitter px + Kalman
UFLD baseline0.8810.8811.511.19
UFLD baseline +CT0.8830.8841.811.44
UFLD v0.2 weighted0.8720.8741.451.19
UFLD v0.3 gated0.8830.8831.581.25
UFLD v0.4 coord0.8800.8801.481.20
UFLD v0.6 aligned0.8800.8791.751.39
UFLD v0.7 ConvGRU0.8950.8941.631.31
Lite baseline0.2180.2151.771.26
Lite baseline +CT0.3120.3092.682.11
Lite v0.5 warped0.7000.7001.831.46
Lite v0.6 ConvGRU0.5410.5402.001.57
Temporal modelCompared withSeedsΔ lane F195 % CIWilcoxon pHolm pVerdict
UFLD v0.2 weightedUFLD baseline + Kalman2-0.010[-0.089, +0.069]0.5001.000underpowered
UFLD v0.3 gatedUFLD baseline + Kalman2+0.002[-0.146, +0.149]1.0001.000underpowered
UFLD v0.4 coordUFLD baseline + Kalman2-0.002[-0.226, +0.223]1.0001.000underpowered
UFLD v0.6 alignedUFLD baseline + Kalman2-0.002[-0.119, +0.115]1.0001.000underpowered
UFLD v0.7 ConvGRUUFLD baseline + Kalman2+0.013[-0.131, +0.157]0.5001.000underpowered
Lite v0.5 warpedLite baseline + Kalman2+0.486[+0.321, +0.650]0.5001.000underpowered
Lite v0.6 ConvGRULite baseline + Kalman2+0.326[+0.171, +0.481]0.5001.000underpowered

When the current frame is degraded

The held-out test scenes again, but every current frame is corrupted (an occluding box, strong blur, darkening or noise; the same corruption for every model) while the earlier frames stay clean. This is where earlier frames should pay off: a single-frame model only sees the damaged image. Validation-tuned post-processing, nothing re-tuned.

Held-out lane F1 with a degraded current frame

0.00.20.40.60.81.0UFLD baseline0.850UFLD baseline +CT0.849UFLD v0.2 weighted0.847UFLD v0.3 gated0.886UFLD v0.4 coord0.855UFLD v0.6 aligned0.884UFLD v0.7 ConvGRU0.874Lite baseline0.163Lite baseline +CT0.243Lite v0.5 warped0.679Lite v0.6 ConvGRU0.520
ModelCleanDegradedoccludeblurdarkennoiseDegraded + Kalman
UFLD baseline0.8810.8500.7610.8910.8690.8840.852
UFLD baseline +CT0.8830.8490.7420.8940.8730.8910.850
UFLD v0.2 weighted0.8720.8470.7560.9010.8590.8780.846
UFLD v0.3 gated0.8830.8860.8750.9020.8720.8930.888
UFLD v0.4 coord0.8800.8550.7650.8990.8740.8850.850
UFLD v0.6 aligned0.8800.8840.8640.9070.8740.8900.886
UFLD v0.7 ConvGRU0.8950.8740.8020.9150.8830.8990.873
Lite baseline0.2180.1630.1470.1880.1500.1690.179
Lite baseline +CT0.3120.2430.2310.2590.2330.2500.261
Lite v0.5 warped0.7000.6790.6700.7020.6710.6730.680
Lite v0.6 ConvGRU0.5410.5200.5350.5250.5230.4980.522

Recurrent models with a carried state

Held-out lane F1 when the ConvGRU keeps one state per stream across the whole scene, minus the window mode used in training (a zero state at every clip).

ModelCarry − windowSeeds
Lite v0.6 ConvGRU-0.48322
UFLD v0.7 ConvGRU-0.02802

Is it the history?

Test-time ablation: history frames replaced by the current frame. The gain is what the real history contributes to each trained model.

Temporal modelF1 gain from real historySeeds
Lite v0.5 warped+0.02002
Lite v0.6 ConvGRU+0.01732
UFLD v0.2 weighted+0.00062
UFLD v0.3 gated+0.01212
UFLD v0.4 coord+0.00332
UFLD v0.6 aligned+0.00762
UFLD v0.7 ConvGRU+0.00492

Where temporal information should help

Held-out lane F1 per scene condition from the ELAS scene tags (whole scenes, so these are three scenes, not frame-level subsets) and jitter, the mean frame-to-frame change of the predicted lane position (lower is steadier; it also contains real lane motion).

Modelocclusiontransitionjitter px
UFLD baseline0.7410.9481.51
UFLD baseline +CT0.7720.9371.81
UFLD v0.2 weighted0.7420.9341.45
UFLD v0.3 gated0.7710.9381.58
UFLD v0.4 coord0.7660.9351.48
UFLD v0.6 aligned0.7600.9381.75
UFLD v0.7 ConvGRU0.7910.9451.63
Lite baseline0.0600.2941.77
Lite baseline +CT0.1190.4052.68
Lite v0.5 warped0.4350.8291.83
Lite v0.6 ConvGRU0.2500.6812.00

The lite family with a longer budget

Lite family, v0.4 recipe, up to 16 epochs (patience 4), 2 seeds, no HPO. Indicative only.

Head to head on the held-out roads

0.00.20.40.60.81.0UFLD baseline (4 ep)0.881UFLD baseline +CT (4 ep)0.883UFLD v0.2 weighted (4 ep)0.872UFLD v0.3 gated (4 ep)0.883UFLD v0.4 coord (4 ep)0.880UFLD v0.6 aligned (4 ep)0.880UFLD v0.7 ConvGRU (4 ep)0.895Lite baseline (16 ep)0.322Lite baseline +CT (16 ep)0.322Lite v0.5 warped (16 ep)0.850Lite v0.5 static (16 ep)0.752Lite v0.6 ConvGRU (16 ep)0.561

Same split, recipe and evaluation; the numbers in brackets are the maximum epochs of each run (early stopping may end sooner). The lite models come from elas_lite_long, the others from elas_pilot_v2.

Held-out test scenes (mean ± std over seeds)

ModelLane F1 @0.5Lane F1 @0.35Pixel F1Anchor F1Jitter pxFPFN
Lite baseline0.322 ± 0.0180.518 ± 0.0250.497 ± 0.0090.676 ± 0.0072.83 ± 0.233532 ± 943532 ± 94
Lite baseline +CT0.322 ± 0.0200.519 ± 0.0270.506 ± 0.0030.674 ± 0.0063.32 ± 0.303534 ± 1053534 ± 105
Lite v0.5 warped0.850 ± 0.0090.935 ± 0.0130.788 ± 0.0090.940 ± 0.0112.19 ± 0.08782 ± 47782 ± 47
Lite v0.5 static0.752 ± 0.1770.876 ± 0.1160.735 ± 0.0740.899 ± 0.0652.89 ± 0.631292 ± 9231292 ± 923
Lite v0.6 ConvGRU0.561 ± 0.0270.726 ± 0.0370.646 ± 0.0150.811 ± 0.0012.59 ± 0.322286 ± 1412286 ± 141

Temporal model minus its single-frame baseline (held-out lane F1)

-0.61-0.31+0.00+0.31+0.61Lite v0.5 warped − Lite baseline+0.528Lite v0.6 ConvGRU − Lite baseline+0.239
Temporal modelCompared withSeedsΔ lane F195 % CIWilcoxon pHolm pVerdict
Lite v0.5 warpedLite baseline2+0.528[+0.446, +0.609]0.5001.000underpowered
Lite v0.6 ConvGRULite baseline2+0.239[-0.167, +0.645]0.5001.000underpowered

Equal-training control

Temporal models start from their baseline's best checkpoint and train further. The +CT baseline gets the same extra training; a temporal gain that survives this comparison is not an effect of more epochs.

-0.62-0.31+0.00+0.31+0.62Lite v0.5 warped − Lite baseline +CT+0.528Lite v0.6 ConvGRU − Lite baseline +CT+0.239Lite baseline +CT − Lite baseline-0.000
ModelCompared withSeedsΔ lane F195 % CIWilcoxon pHolm pVerdict
Lite v0.5 warpedLite baseline +CT2+0.528[+0.427, +0.629]0.5001.000underpowered
Lite v0.6 ConvGRULite baseline +CT2+0.239[-0.186, +0.665]0.5001.000underpowered
Lite baseline +CTLite baseline2-0.000[-0.020, +0.019]1.0001.000underpowered

Capacity control: extra layers or earlier frames?

Lite v0.5 static is lite v0.5 with every history frame replaced by the current frame, in training and at test time: the same layers, warm start and budget, but no temporal information. "Lite v0.5 − static" is what the earlier frames add; "static − baseline" is what the extra fusion layers add on their own.

-0.65-0.33+0.00+0.33+0.65Lite v0.5 static − Lite baseline+0.430Lite v0.5 warped − Lite v0.5 static+0.098
ModelCompared withSeedsΔ lane F195 % CIWilcoxon pHolm pVerdict
Lite v0.5 staticLite baseline2+0.430[-1.324, +2.184]0.5001.000underpowered
Lite v0.5 warpedLite v0.5 static2+0.098[-1.575, +1.770]1.0001.000underpowered

Against the Kalman tracker

The same predictions filtered by the output Kalman tracker (tuned on validation). This is what time gives almost for free; a learned temporal model should beat its baseline + Kalman (paired table below).

ModelLane F1Lane F1 + KalmanJitter pxJitter px + Kalman
Lite baseline0.3220.3212.831.94
Lite baseline +CT0.3220.3223.321.87
Lite v0.5 warped0.8500.8472.191.74
Lite v0.5 static0.7520.7502.892.31
Lite v0.6 ConvGRU0.5610.5582.591.97
Temporal modelCompared withSeedsΔ lane F195 % CIWilcoxon pHolm pVerdict
Lite v0.5 warpedLite baseline + Kalman2+0.529[+0.434, +0.624]0.5001.000underpowered
Lite v0.5 staticLite baseline + Kalman2+0.432[-1.336, +2.199]0.5001.000underpowered
Lite v0.6 ConvGRULite baseline + Kalman2+0.241[-0.179, +0.660]0.5001.000underpowered

When the current frame is degraded

The held-out test scenes again, but every current frame is corrupted (an occluding box, strong blur, darkening or noise; the same corruption for every model) while the earlier frames stay clean. This is where earlier frames should pay off: a single-frame model only sees the damaged image. Validation-tuned post-processing, nothing re-tuned.

Held-out lane F1 with a degraded current frame

0.00.20.40.60.81.0Lite baseline0.261Lite baseline +CT0.271Lite v0.5 warped0.842Lite v0.5 static0.679Lite v0.6 ConvGRU0.563
ModelCleanDegradedoccludeblurdarkennoiseDegraded + Kalman
Lite baseline0.3220.2610.2540.2580.2630.2680.277
Lite baseline +CT0.3220.2710.2580.2700.2870.2720.287
Lite v0.5 warped0.8500.8420.8290.8660.8360.8380.840
Lite v0.5 static0.7520.6790.5540.7310.7410.6970.688
Lite v0.6 ConvGRU0.5610.5630.5540.5600.5910.5470.561

Recurrent models with a carried state

Held-out lane F1 when the ConvGRU keeps one state per stream across the whole scene, minus the window mode used in training (a zero state at every clip).

ModelCarry − windowSeeds
Lite v0.6 ConvGRU-0.15402

Is it the history?

Test-time ablation: history frames replaced by the current frame. The gain is what the real history contributes to each trained model.

Temporal modelF1 gain from real historySeeds
Lite v0.5 warped+0.00422
Lite v0.6 ConvGRU+0.00862

Fixing the UFLD overfitting

The first pilot showed every UFLD run peaking at epoch 1. Each arm below changes one thing in the training of the UFLD baseline (same split, seeds, epochs and evaluation) and is compared with the original recipe (photometric augmentation). The recipe for later runs is chosen on the validation column; the held-out column is reported, never used for choosing. "Best epochs" are the validation-selected epochs per seed; the "more scenes" arm has its own, larger validation set. Three seeds cannot reach significance, so the verdicts are indicative.

Held-out lane F1 per arm

0.00.20.40.60.81.0geometric0.858geometric flip0.769more scenes (18)0.129small head (256)0.210photometric extended0.150frozen stem + layer10.083current-frame degradation0.094photometric0.068none0.068backbone lr ×0.10.050regularised0.002
ArmValidation lane F1Held-out lane F1Best epochsHeld-out Δ vs reference
geometric0.772 ± 0.0070.858 ± 0.0024, 4, 4+0.790 underpowered
geometric flip0.768 ± 0.0010.769 ± 0.0164, 4, 4+0.701 underpowered
more scenes (18)0.288 ± 0.0320.129 ± 0.0231, 2, 2+0.061 underpowered
small head (256)0.248 ± 0.0260.210 ± 0.0231, 1, 1+0.142 underpowered
photometric extended0.175 ± 0.0070.150 ± 0.0161, 1, 1+0.082 underpowered
frozen stem + layer10.170 ± 0.0210.083 ± 0.0121, 1, 1+0.015 underpowered
current-frame degradation0.163 ± 0.0200.094 ± 0.0401, 1, 1+0.026 underpowered
photometric0.161 ± 0.0340.068 ± 0.0442, 2, 1reference
none0.150 ± 0.0220.068 ± 0.0432, 1, 1+0.000 underpowered
backbone lr ×0.10.149 ± 0.0140.050 ± 0.0041, 1, 1-0.019 underpowered
regularised0.019 ± 0.0230.002 ± 0.0031, 1, 1-0.066 underpowered

How far back to look

History-length ablation: every arm uses the same split (purge gap large enough for the longest history) and the same trained baseline, so only the temporal context changes. Cells are means over seeds on the held-out scenes; "not run" arms can be added with ablate --only.

UFLD v0.4 coord: lane F1 gain over UFLD baseline

frame step (history frame k is t - k x step)2510frames in the clip3+0.029+0.028+0.0275not run+0.004not run

UFLD v0.4 coord: held-out lane F1

frame step2510frames in the clip30.8600.8590.8585not run0.834not run

Training curves

Temporal models and +CT controls start from their family baseline's best checkpoint.

UFLD baseline

0.000.250.500.751.001234
validation lane F1 per epoch; solid = first seed, dashed = second, dot = best epoch (the checkpoint kept)

UFLD baseline +CT

0.000.250.500.751.001234
validation lane F1 per epoch; solid = first seed, dashed = second, dot = best epoch (the checkpoint kept)

UFLD v0.2 weighted

0.000.250.500.751.001234
validation lane F1 per epoch; solid = first seed, dashed = second, dot = best epoch (the checkpoint kept)

UFLD v0.3 gated

0.000.250.500.751.001234
validation lane F1 per epoch; solid = first seed, dashed = second, dot = best epoch (the checkpoint kept)

UFLD v0.4 coord

0.000.250.500.751.001234
validation lane F1 per epoch; solid = first seed, dashed = second, dot = best epoch (the checkpoint kept)

UFLD v0.6 aligned

0.000.250.500.751.001234
validation lane F1 per epoch; solid = first seed, dashed = second, dot = best epoch (the checkpoint kept)

UFLD v0.7 ConvGRU

0.000.250.500.751.001234
validation lane F1 per epoch; solid = first seed, dashed = second, dot = best epoch (the checkpoint kept)

Lite baseline

0.000.250.500.751.001234
validation lane F1 per epoch; solid = first seed, dashed = second, dot = best epoch (the checkpoint kept)

Lite baseline +CT

0.000.250.500.751.001234
validation lane F1 per epoch; solid = first seed, dashed = second, dot = best epoch (the checkpoint kept)

Lite v0.5 warped

0.000.250.500.751.001234
validation lane F1 per epoch; solid = first seed, dashed = second, dot = best epoch (the checkpoint kept)

Lite v0.6 ConvGRU

0.000.250.500.751.001234
validation lane F1 per epoch; solid = first seed, dashed = second, dot = best epoch (the checkpoint kept)

Streaming on a held-out road

240 consecutive frames of scene BR_S02 (never seen in training), run frame by frame through the streaming detector: left UFLD baseline, right Lite v0.5 with cached history features (first pilot checkpoints). Red = ego-left slot, yellow = ego-right slot, numbers = mean existence probability of each lane.

Latency and real-time budgets

Measured at batch 1 on NVIDIA GeForce RTX 3050 with 640×480 frames of the held-out clip (first pilot checkpoints). "cached" reuses the stored features of previous frames; "recompute" re-encodes all three frames every time. Preprocessing (a PIL bilinear resize on the CPU, identical to training) is the largest cost.

0510152025UFLD baseline · single19.1 msUFLD v0.2 weighted · cached17.9 msUFLD v0.2 weighted · recompute26.7 msUFLD v0.3 gated · cached17.0 msUFLD v0.3 gated · recompute26.9 msUFLD v0.4 coord · cached16.9 msUFLD v0.4 coord · recompute27.2 msLite baseline · single14.0 msLite v0.5 warped · cached18.3 msLite v0.5 warped · recompute25.7 ms
preprocessmodelpostprocess

Simulated 30 FPS camera: service times = measured × slowdown. The Jetson slowdowns are assumptions from peak-throughput ratios, not measurements on a Jetson. "History fallbacks" are frames whose history frames were skipped because the worker was busy.

ProfileSlowdownModelModeProcessed FPSp95 latency msHistory fallbacksBudgets
desktop×1.0UFLD baselinesingle30.022.30 %met
desktop×1.0UFLD v0.2 weightedcached30.022.00 %met
desktop×1.0UFLD v0.2 weightedrecompute30.030.10 %met
desktop×1.0UFLD v0.3 gatedcached30.022.60 %met
desktop×1.0UFLD v0.3 gatedrecompute30.030.30 %met
desktop×1.0UFLD v0.4 coordcached30.021.70 %met
desktop×1.0UFLD v0.4 coordrecompute30.038.50 %met
desktop×1.0Lite baselinesingle30.018.20 %met
desktop×1.0Lite v0.5 warpedcached30.024.10 %met
desktop×1.0Lite v0.5 warpedrecompute30.033.70 %met
jetson_agx_orin_assumed×1.7UFLD baselinesingle29.050.40 %missed
jetson_agx_orin_assumed×1.7UFLD v0.2 weightedcached28.759.14 %missed
jetson_agx_orin_assumed×1.7UFLD v0.2 weightedrecompute24.975.418 %missed
jetson_agx_orin_assumed×1.7UFLD v0.3 gatedcached28.461.35 %missed
jetson_agx_orin_assumed×1.7UFLD v0.3 gatedrecompute24.277.221 %missed
jetson_agx_orin_assumed×1.7UFLD v0.4 coordcached29.051.63 %missed
jetson_agx_orin_assumed×1.7UFLD v0.4 coordrecompute25.274.217 %missed
jetson_agx_orin_assumed×1.7Lite baselinesingle29.033.80 %met
jetson_agx_orin_assumed×1.7Lite v0.5 warpedcached27.268.810 %missed
jetson_agx_orin_assumed×1.7Lite v0.5 warpedrecompute20.585.833 %missed
jetson_orin_nano_assumed×7.0UFLD baselinesingle7.8186.50 %missed
jetson_orin_nano_assumed×7.0UFLD v0.2 weightedcached7.6196.582 %missed
jetson_orin_nano_assumed×7.0UFLD v0.2 weightedrecompute6.1218.185 %missed
jetson_orin_nano_assumed×7.0UFLD v0.3 gatedcached7.4200.679 %missed
jetson_orin_nano_assumed×7.0UFLD v0.3 gatedrecompute5.8228.792 %missed
jetson_orin_nano_assumed×7.0UFLD v0.4 coordcached7.5202.679 %missed
jetson_orin_nano_assumed×7.0UFLD v0.4 coordrecompute5.9240.687 %missed
jetson_orin_nano_assumed×7.0Lite baselinesingle9.4168.70 %missed
jetson_orin_nano_assumed×7.0Lite v0.5 warpedcached7.7199.380 %missed
jetson_orin_nano_assumed×7.0Lite v0.5 warpedrecompute5.8243.987 %missed

Export and precision checks

Each exported model runs the same frames as PyTorch through the same streaming code (first pilot checkpoints). Val lane F1 is measured on 240 validation frames with the exact training-time temporal context; the difference to PyTorch FP32 is in brackets. TensorRT ran on the development GPU, not on a Jetson.

ModelBackendmax |Δ logits|max |Δ exist|mean lane Δx pxVal lane F1Numerics
Lite v0.5 warpedonnxruntime fp327.6e-063.6e-070.000.5636 (+0.0000)within tolerance
Lite v0.5 warpedonnxruntime int87.6e-066.4e-021.360.5570 (-0.0066)outside tolerance
Lite v0.5 warpedtensorrt fp321.8e-031.2e-040.000.5636 (+0.0000)outside tolerance
Lite v0.5 warpedtensorrt fp165.9e-021.3e-030.010.5636 (+0.0000)outside tolerance
Lite v0.5 warpedtensorrt int81.3e-022.1e-020.360.5658 (+0.0022)outside tolerance
UFLD baselineonnxruntime fp322.4e-063.0e-070.000.1732 (+0.0000)within tolerance
UFLD baselineonnxruntime int83.5e-013.6e-022.290.1776 (+0.0044)outside tolerance
UFLD baselinetensorrt fp324.7e-046.4e-050.000.1732 (+0.0000)within tolerance
UFLD baselinetensorrt fp168.7e-036.2e-040.020.1732 (+0.0000)within tolerance
UFLD baselinetensorrt int81.7e-011.7e-020.540.1732 (+0.0000)outside tolerance
UFLD v0.2 weightedonnxruntime fp321.4e-061.8e-070.000.0789 (+0.0000)within tolerance
UFLD v0.2 weightedonnxruntime int81.4e-065.1e-030.720.0636 (-0.0154)outside tolerance
UFLD v0.2 weightedtensorrt fp325.5e-042.5e-050.000.0789 (+0.0000)within tolerance
UFLD v0.2 weightedtensorrt fp165.7e-033.7e-040.010.0789 (+0.0000)within tolerance
UFLD v0.2 weightedtensorrt int86.9e-041.0e-020.410.0768 (-0.0022)outside tolerance

Examples from the held-out scenes

UFLD baseline successe example
UFLD baseline, held-out test, a typical success: original | ground truth (green) | prediction (red) - VV_S03_786
UFLD baseline error example
UFLD baseline, held-out test, a typical error: original | ground truth (green) | prediction (red) - VIX_S05_52
UFLD v0.7 ConvGRU successe example
UFLD v0.7 ConvGRU, held-out test, a typical success: original | ground truth (green) | prediction (red) - VV_S03_775
UFLD v0.7 ConvGRU error example
UFLD v0.7 ConvGRU, held-out test, a typical error: original | ground truth (green) | prediction (red) - VIX_S05_51

Roadmap

First make a lightweight temporal model beat the UFLD baseline under the full protocol; only then optimise for an in-car embedded system.

Phase 1: protocol and first pilot (v0.3)

  • doneLeakage-safe ELAS protocol: three held-out road scenes, 60-frame blocks with a purge gap, six seeds, HPO with the same budget for every model, validation-only selection.
  • doneGPU pilot (2 seeds, up to 4 epochs): lite v0.5 is best on unseen roads; every UFLD run peaks at epoch 1 and then overfits; history adds little to any model.
  • doneDeployment tooling: ONNX, TensorRT FP32 / FP16 / INT8 on the desktop GPU, streaming with cached history features.

Phase 2: make a lightweight temporal model beat the UFLD baseline (v0.4)

  • doneFix the UFLD overfitting: geometric augmentation lifts the UFLD baseline from 0.07 to 0.86 held-out lane F1 (configs/ablations/augmentation.yaml, chosen on validation); extended photometric augmentation, flips and dropout + label smoothing do not help.
  • doneThe other overfitting levers as single changes to the original recipe: a 10x lower backbone learning rate, frozen early layers, a smaller UFLD head, current-frame degradation and 8 more ELAS training scenes. None fixes the overfitting on its own (held-out lane F1 0.05 to 0.21, best epoch still 1 or 2); geometric augmentation stays the recipe. Cross-dataset initialisation (model.init_checkpoint) is implemented for when CULane / TuSimple weights are available.
  • doneLonger history (configs/ablations/history.yaml, UFLD v0.4, 4 arms): steps of 2, 5 and 10 frames give the same gain over the baseline (about +0.03); 5 frames instead of 3 remove it. More arms of the grid (steps 1 to 15, 2 to 5 frames) can be added with ablate --only.
  • doneCurrent-frame degradation: only the current frame is occluded, blurred, darkened or made noisy while the history stays clean, so a temporal model must use its history (data.augmentation.current_frame_prob).
  • doneAlign before fusing: UFLD v0.6 (lite v0.5's learned warp and gate on UFLD features).
  • doneRecurrent state: UFLD v0.7 and lite v0.6 (ConvGRU); streaming can carry one state per camera (--mode carry).
  • doneEqual-training controls: the +CT baselines get the same extra training as the temporal models.
  • doneEvaluate where time should help: lane F1 per scene condition, jitter, and a validation-tuned Kalman tracker as the cheap temporal reference.
  • doneSecond pilot with the v0.4 models and recipe (configs/elas_pilot_v2.yaml): UFLD baseline 0.881, best temporal UFLD (v0.7) 0.895; the lite models need more epochs.
  • doneCapacity control lite_v05_static: lite v0.5 fed the current frame in every position, to separate a temporal gain from the extra fusion layers.
  • doneLite family with a longer budget (up to 16 epochs) and the capacity control (configs/elas_lite_long.yaml): lite v0.5 reaches 0.850 with 8x fewer parameters than UFLD; under an occluded current frame its history is worth +0.17 and +0.38 over the no-history control.
  • doneRobustness evaluation: current frame occluded, blurred, darkened or noisy with a clean history. Under occlusion UFLD v0.3 keeps 0.875 lane F1 against 0.761 for the baseline, in both seeds.
  • nextTrain the recurrent models on long sequences so that one carried state per camera works (carry mode drifts after 3-frame training).

Phase 3: full protocol (supervisor)

  • nextFull run: 6 seeds, HPO, up to 50 epochs, with the recipe and models chosen from the pilots (configs/elas.yaml).
  • laterPretraining on CULane / TuSimple, then fine-tuning on ELAS (needs the datasets or the official UFLD weights).

Phase 4: embedded automotive deployment (last step)

  • laterMeasure on the real device: build the TensorRT engines on a Jetson and run the measurement script; today's Jetson figures are simulations with assumed slowdowns.
  • laterTake preprocessing off the CPU: the CPU resize is about 9 ms of a 14 to 19 ms frame. Resize on the camera's image processor or the GPU with zero-copy buffers, and retrain with that same resize.
  • laterCrop to the road: the row anchors cover only the lower 41 % of the image, so cropping cuts compute by about 2.4 times; a lower input resolution is the second option. Both need retraining.
  • laterTensorRT FP16 by default (lossless in the pilot); INT8 only if FP16 is too slow, calibrated on the car's camera or with quantization-aware training for the lite models.
  • laterPrefer the lite family: about 8 times fewer parameters and 3.6 times less compute than UFLD.
  • laterRobustness to dropped frames: train with frame drops and space the history by timestamps, since the car's camera may run at a different frame rate than ELAS.
  • laterProduction runtime: C++ TensorRT or DeepStream instead of Python, capture / inference / post-processing in parallel, always process the latest frame, locked clocks, thermal tests inside the enclosure.

Reproduce and continue

python -m tac_ufld doctor
python -m pytest -q
python -m tac_ufld ablate --spec configs/ablations/augmentation.yaml --confirm   # overfitting remedies
python -m tac_ufld run --config configs/elas_pilot_v2.yaml                       # pilot with the v0.4 models
python -m tac_ufld ablate --spec configs/ablations/history.yaml --confirm        # history length
python -m tac_ufld run --config configs/elas.yaml --confirm                      # full protocol
python -m tac_ufld ui                                                            # inspect checkpoints
python -m tac_ufld site --runs results/elas_pilot_v2                             # rebuild this page

The full experiment differs from the pilots in seeds (6 instead of 2), epochs (up to 50 with patience 10) and hyper-parameter search (the same budget for every model). Only the full run can support claims.